/// <summary> /// Initializes a new instance of the <see cref="TypeToRegister"/> class, specifying the origin types. /// </summary> /// <param name="type">The type to register.</param> /// <param name="recursiveOriginType">The type whose recursive processing of <paramref name="memberTypesToInclude"/> and <paramref name="relatedTypesToInclude"/> resulted in the creation of this <see cref="TypeToRegister"/>.</param> /// <param name="directOriginType">The type whose processing of <paramref name="memberTypesToInclude"/> and <paramref name="relatedTypesToInclude"/> directly resulted in the creation of this <see cref="TypeToRegister"/>.</param> /// <param name="memberTypesToInclude">Specifies which member types of <paramref name="type"/> that should also be registered.</param> /// <param name="relatedTypesToInclude">Specifies which types related to <paramref name="type"/> that should also be registered.</param> protected TypeToRegister( Type type, Type recursiveOriginType, Type directOriginType, MemberTypesToInclude memberTypesToInclude, RelatedTypesToInclude relatedTypesToInclude) { if (type == null) { throw new ArgumentNullException(nameof(type)); } if (recursiveOriginType == null) { throw new ArgumentNullException(nameof(recursiveOriginType)); } if (directOriginType == null) { throw new ArgumentNullException(nameof(directOriginType)); } this.Type = type; this.RecursiveOriginType = recursiveOriginType; this.DirectOriginType = directOriginType; this.MemberTypesToInclude = memberTypesToInclude; this.RelatedTypesToInclude = relatedTypesToInclude; }
/// <inheritdoc /> protected sealed override TypeToRegister BuildTypeToRegisterForPostInitializationRegistration( Type type, Type recursiveOriginType, Type directOriginType, MemberTypesToInclude memberTypesToInclude, RelatedTypesToInclude relatedTypesToInclude) { if (type == null) { throw new ArgumentNullException(nameof(type)); } if (recursiveOriginType == null) { throw new ArgumentNullException(nameof(recursiveOriginType)); } if (directOriginType == null) { throw new ArgumentNullException(nameof(directOriginType)); } var genericTypeDefinition = type.GetGenericTypeDefinition(); var genericTypeDefinitionTypeToRegister = (TypeToRegisterForPropertyBag)this.RegisteredTypeToRegistrationDetailsMap[genericTypeDefinition].TypeToRegister; var result = new TypeToRegisterForPropertyBag(type, recursiveOriginType, directOriginType, memberTypesToInclude, relatedTypesToInclude, genericTypeDefinitionTypeToRegister.StringSerializerBuilderFunc); return(result); }
/// <summary> /// Initializes a new instance of the <see cref="TypeToRegister"/> class with a type that is it's own origin. /// </summary> /// <param name="type">The type to register.</param> /// <param name="memberTypesToInclude">Specifies which member types of <paramref name="type"/> that should also be registered.</param> /// <param name="relatedTypesToInclude">Specifies which types related to <paramref name="type"/> that should also be registered.</param> protected TypeToRegister( Type type, MemberTypesToInclude memberTypesToInclude, RelatedTypesToInclude relatedTypesToInclude) : this(type, type, type, memberTypesToInclude, relatedTypesToInclude) { }
/// <summary> /// Initializes a new instance of the <see cref="TypeToRegisterForPropertyBag{T}"/> class. /// </summary> /// <param name="memberTypesToInclude">Specifies which member types of <typeparamref name="T"/> that should also be registered.</param> /// <param name="relatedTypesToInclude">Specifies which types related to <typeparamref name="T"/> that should also be registered.</param> /// <param name="stringSerializerBuilderFunc">A func that builds the <see cref="IStringSerializeAndDeserialize"/>.</param> public TypeToRegisterForPropertyBag( MemberTypesToInclude memberTypesToInclude, RelatedTypesToInclude relatedTypesToInclude, Func <IStringSerializeAndDeserialize> stringSerializerBuilderFunc) : base(typeof(T), memberTypesToInclude, relatedTypesToInclude, stringSerializerBuilderFunc) { }
/// <summary> /// Initializes a new instance of the <see cref="TypeToRegisterForBson{T}"/> class. /// </summary> /// <param name="memberTypesToInclude">Specifies which member types of <typeparamref name="T"/> that should also be registered.</param> /// <param name="relatedTypesToInclude">Specifies which types related to <typeparamref name="T"/> that should also be registered.</param> /// <param name="bsonSerializerBuilder">Builds an<see cref="IBsonSerializer"/>.</param> /// <param name="propertyNameWhitelist">The names of the properties to constrain the registration to.</param> public TypeToRegisterForBson( MemberTypesToInclude memberTypesToInclude, RelatedTypesToInclude relatedTypesToInclude, BsonSerializerBuilder bsonSerializerBuilder, IReadOnlyCollection <string> propertyNameWhitelist) : base(typeof(T), memberTypesToInclude, relatedTypesToInclude, bsonSerializerBuilder, propertyNameWhitelist) { }
/// <summary> /// Initializes a new instance of the <see cref="TypeToRegisterForJson{T}"/> class. /// </summary> /// <param name="memberTypesToInclude">Specifies which member types of <typeparamref name="T"/> that should also be registered.</param> /// <param name="relatedTypesToInclude">Specifies which types related to <typeparamref name="T"/> that should also be registered.</param> /// <param name="jsonConverterBuilder">Builds a serializing and deserializing <see cref="JsonConverter"/>.</param> /// <param name="keyInDictionaryStringSerializer">The serializer to use when dictionaries are keyed on <typeparamref name="T"/> and the keys should be written-to/read-from a string.</param> public TypeToRegisterForJson( MemberTypesToInclude memberTypesToInclude, RelatedTypesToInclude relatedTypesToInclude, JsonConverterBuilder jsonConverterBuilder, IStringSerializeAndDeserialize keyInDictionaryStringSerializer) : base(typeof(T), memberTypesToInclude, relatedTypesToInclude, jsonConverterBuilder, keyInDictionaryStringSerializer) { }
/// <summary> /// Initializes a new instance of the <see cref="TypeToRegisterForPropertyBag"/> class with a type that is it's own origin. /// </summary> /// <param name="type">The type to register.</param> /// <param name="memberTypesToInclude">Specifies which member types of <paramref name="type"/> that should also be registered.</param> /// <param name="relatedTypesToInclude">Specifies which types related to <paramref name="type"/> that should also be registered.</param> /// <param name="stringSerializerBuilderFunc">A func that builds the <see cref="IStringSerializeAndDeserialize"/>.</param> public TypeToRegisterForPropertyBag( Type type, MemberTypesToInclude memberTypesToInclude, RelatedTypesToInclude relatedTypesToInclude, Func <IStringSerializeAndDeserialize> stringSerializerBuilderFunc) : this(type, type, type, memberTypesToInclude, relatedTypesToInclude, stringSerializerBuilderFunc) { }
/// <summary> /// Initializes a new instance of the <see cref="TypeToRegisterForJson"/> class, specifying the origin types. /// </summary> /// <param name="type">The type to register.</param> /// <param name="recursiveOriginType">The type whose recursive processing of <paramref name="memberTypesToInclude"/> and <paramref name="relatedTypesToInclude"/> resulted in the creation of this <see cref="TypeToRegisterForJson"/>.</param> /// <param name="directOriginType">The type whose processing of <paramref name="memberTypesToInclude"/> and <paramref name="relatedTypesToInclude"/> directly resulted in the creation of this <see cref="TypeToRegisterForJson"/>.</param> /// <param name="memberTypesToInclude">Specifies which member types of <paramref name="type"/> that should also be registered.</param> /// <param name="relatedTypesToInclude">Specifies which types related to <paramref name="type"/> that should also be registered.</param> /// <param name="jsonConverterBuilder">Builds a serializing and deserializing <see cref="JsonConverter"/>.</param> /// <param name="keyInDictionaryStringSerializer">The serializer to use when dictionaries are keyed on <paramref name="type"/> and the keys should be written-to/read-from a string.</param> public TypeToRegisterForJson( Type type, Type recursiveOriginType, Type directOriginType, MemberTypesToInclude memberTypesToInclude, RelatedTypesToInclude relatedTypesToInclude, JsonConverterBuilder jsonConverterBuilder, IStringSerializeAndDeserialize keyInDictionaryStringSerializer) : base(type, recursiveOriginType, directOriginType, memberTypesToInclude, relatedTypesToInclude) { if (type == null) { throw new ArgumentNullException(nameof(type)); } if (recursiveOriginType == null) { throw new ArgumentNullException(nameof(recursiveOriginType)); } if (directOriginType == null) { throw new ArgumentNullException(nameof(directOriginType)); } if (jsonConverterBuilder != null) { if (memberTypesToInclude != MemberTypesToInclude.None) { throw new ArgumentException(Invariant($"{nameof(jsonConverterBuilder)} is specified, but {nameof(Serialization.MemberTypesToInclude)} is not {MemberTypesToInclude.None}.")); } if (type.IsGenericTypeDefinition) { throw new NotSupportedException(Invariant($"{nameof(jsonConverterBuilder)} is specified, but underlying type to register is an open generic.")); } } if (keyInDictionaryStringSerializer != null) { if (type.IsGenericTypeDefinition) { throw new NotSupportedException(Invariant($"{nameof(keyInDictionaryStringSerializer)} is specified, but underlying type to register is an open generic.")); } } this.JsonConverterBuilder = jsonConverterBuilder; this.KeyInDictionaryStringSerializer = keyInDictionaryStringSerializer; }
/// <summary> /// Initializes a new instance of the <see cref="TypeToRegisterForPropertyBag"/> class, specifying the origin types. /// </summary> /// <param name="type">The type to register.</param> /// <param name="recursiveOriginType">The type whose recursive processing of <paramref name="memberTypesToInclude"/> and <paramref name="relatedTypesToInclude"/> resulted in the creation of this <see cref="TypeToRegisterForPropertyBag"/>.</param> /// <param name="directOriginType">The type whose processing of <paramref name="memberTypesToInclude"/> and <paramref name="relatedTypesToInclude"/> directly resulted in the creation of this <see cref="TypeToRegisterForPropertyBag"/>.</param> /// <param name="memberTypesToInclude">Specifies which member types of <paramref name="type"/> that should also be registered.</param> /// <param name="relatedTypesToInclude">Specifies which types related to <paramref name="type"/> that should also be registered.</param> /// <param name="stringSerializerBuilderFunc">A func that builds the <see cref="IStringSerializeAndDeserialize"/>.</param> public TypeToRegisterForPropertyBag( Type type, Type recursiveOriginType, Type directOriginType, MemberTypesToInclude memberTypesToInclude, RelatedTypesToInclude relatedTypesToInclude, Func <IStringSerializeAndDeserialize> stringSerializerBuilderFunc) : base(type, recursiveOriginType, directOriginType, memberTypesToInclude, relatedTypesToInclude) { if (type == null) { throw new ArgumentNullException(nameof(type)); } if (recursiveOriginType == null) { throw new ArgumentNullException(nameof(recursiveOriginType)); } if (directOriginType == null) { throw new ArgumentNullException(nameof(directOriginType)); } if (type.IsGenericTypeDefinition) { throw new NotSupportedException(Invariant($"Open generics are not supported.")); } if (stringSerializerBuilderFunc != null) { if (memberTypesToInclude != MemberTypesToInclude.None) { throw new ArgumentException(Invariant($"{nameof(stringSerializerBuilderFunc)} is specified, but {nameof(Serialization.MemberTypesToInclude)} is not {MemberTypesToInclude.None}.")); } } this.StringSerializerBuilderFunc = stringSerializerBuilderFunc; }
private static IReadOnlyCollection <Type> GetMemberTypesToInclude( Type type, MemberTypesToInclude memberTypesToInclude) { // This is for debugging purposes only. The debugger doesn't like conditional breakpoints on objects // of type Type, so here we are pulling out the name to enable conditional breakpoint on name. var typeName = type.Name; if (memberTypesToInclude == MemberTypesToInclude.None) { return(new Type[0]); } var result = new List <Type>(); if (memberTypesToInclude.HasFlag(MemberTypesToInclude.GenericArguments)) { // Contrary to what is implied in documentation, a constructed generic type can still // contain generic parameters! Also, and likely related, type.GetGenericArguments() can still // return generic parameters! consider... // // private class GenericClassToRegister<T> // { // public IDictionary<string, MyGenericClass<T>> MyProperty { get; set; } // } // // private class MyGenericClass<T> { } // // MemberTypesToInclude.DeclaredProperties will pull-in the type of MyProperty // When calling this method on that type, we observe the following: // // propertyType.IsConstructedGenericType == true // propertyType.ContainsGenericParameters == true // propertyType.IsGenericParameter == false // propertyType.IsGenericTypeDefinition == false // // var dictionaryValueType = propertyType.GetGenericArguments().Last() // dictionaryValueType.IsConstructedGenericType == true // dictionaryValueType.ContainsGenericParameters == true // dictionaryValueType.IsGenericParameter == false // dictionaryValueType.IsGenericTypeDefinition == false // // var genericParameterType = dictionaryValueType.GetGenericArguments().First() // genericParameterType.IsConstructedGenericType == false // genericParameterType.ContainsGenericParameters == true // genericParameterType.IsGenericParameter == true // genericParameterType.IsGenericTypeDefinition == false if (type.IsGenericType) { result.AddRange(type.GenericTypeArguments.Where(_ => !_.IsGenericParameter)); } } if (memberTypesToInclude.HasFlag(MemberTypesToInclude.ArrayElement)) { if (type.IsArray) { // same considerations as in the comment above about generic arguments: // private class GenericClassToRegister<T> // { // public IDictionary<string, MyGenericClass<T>>[] MyProperty { get; set; } // } result.Add(type.GetElementType()); } } // We want to pull generic arguments and array elements from restricted types (e.g. List<MyModel>) // but otherwise we are not interested in the fields and properties of those types, which will // contain a bunch of other System and .NET internal types. if (!IsRestrictedType(type)) { var fieldAndPropertyTypes = type .GetMembersFiltered(MemberRelationships.DeclaredInType, MemberOwners.Instance, MemberAccessModifiers.All, MemberKinds.Field | MemberKinds.Property) .Where(_ => ((_ is PropertyInfo) && memberTypesToInclude.HasFlag(MemberTypesToInclude.DeclaredProperties)) || ((_ is FieldInfo) && memberTypesToInclude.HasFlag(MemberTypesToInclude.DeclaredFields))) .Select(_ => _.GetUnderlyingType()) .ToList(); result.AddRange(fieldAndPropertyTypes); } // there will be open generic types that are not generic type definitions // we can only register the generic type definitions but we want to explore both sets of types // (e.g. the generic type definition of IDictionary<string, MyGenericClass<T>> is IDictionary<,>, // which misses MyGenericClass<>) var genericTypeDefinitions = result .Where(_ => _.IsGenericType && _.ContainsGenericParameters && (!_.IsGenericTypeDefinition)) .Select(_ => _.GetGenericTypeDefinition()) .ToList(); result.AddRange(genericTypeDefinitions); return(result); }
/// <summary> /// Initializes a new instance of the <see cref="TypeToRegisterForBson"/> class, specifying the origin types. /// </summary> /// <param name="type">The type to register.</param> /// <param name="recursiveOriginType">The type whose recursive processing of <paramref name="memberTypesToInclude"/> and <paramref name="relatedTypesToInclude"/> resulted in the creation of this <see cref="TypeToRegisterForBson"/>.</param> /// <param name="directOriginType">The type whose processing of <paramref name="memberTypesToInclude"/> and <paramref name="relatedTypesToInclude"/> directly resulted in the creation of this <see cref="TypeToRegisterForBson"/>.</param> /// <param name="memberTypesToInclude">Specifies which member types of <paramref name="type"/> that should also be registered.</param> /// <param name="relatedTypesToInclude">Specifies which types related to <paramref name="type"/> that should also be registered.</param> /// <param name="bsonSerializerBuilder">Builds an <see cref="IBsonSerializer"/>.</param> /// <param name="propertyNameWhitelist">The names of the properties to constrain the registration to.</param> public TypeToRegisterForBson( Type type, Type recursiveOriginType, Type directOriginType, MemberTypesToInclude memberTypesToInclude, RelatedTypesToInclude relatedTypesToInclude, BsonSerializerBuilder bsonSerializerBuilder, IReadOnlyCollection <string> propertyNameWhitelist) : base(type, recursiveOriginType, directOriginType, memberTypesToInclude, relatedTypesToInclude) { if (type == null) { throw new ArgumentNullException(nameof(type)); } if (recursiveOriginType == null) { throw new ArgumentNullException(nameof(recursiveOriginType)); } if (directOriginType == null) { throw new ArgumentNullException(nameof(directOriginType)); } if ((bsonSerializerBuilder != null) && (propertyNameWhitelist != null)) { throw new ArgumentException(Invariant($"{nameof(bsonSerializerBuilder)} and {nameof(propertyNameWhitelist)} cannot both be specified.")); } if (bsonSerializerBuilder != null) { if (memberTypesToInclude != MemberTypesToInclude.None) { throw new ArgumentException(Invariant($"{nameof(bsonSerializerBuilder)} is specified, but {nameof(Serialization.MemberTypesToInclude)} is not {MemberTypesToInclude.None}.")); } if (type.IsGenericTypeDefinition) { throw new NotSupportedException(Invariant($"{nameof(bsonSerializerBuilder)} is specified, but underlying type to register is an open generic.")); } } if (propertyNameWhitelist != null) { if (!propertyNameWhitelist.Any()) { throw new ArgumentException(Invariant($"'{nameof(propertyNameWhitelist)}' is an empty enumerable")); } if (propertyNameWhitelist.Any(string.IsNullOrWhiteSpace)) { throw new ArgumentException(Invariant($"'{nameof(propertyNameWhitelist)}' contains an element that is null or white space")); } if (memberTypesToInclude != MemberTypesToInclude.None) { throw new ArgumentException(Invariant($"{nameof(propertyNameWhitelist)} is specified, but {nameof(Serialization.MemberTypesToInclude)} is not {MemberTypesToInclude.None}.")); } if (relatedTypesToInclude != RelatedTypesToInclude.None) { throw new ArgumentException(Invariant($"{nameof(propertyNameWhitelist)} is specified, but {nameof(Serialization.RelatedTypesToInclude)} is not {RelatedTypesToInclude.None}.")); } if (type.IsGenericTypeDefinition) { throw new NotSupportedException(Invariant($"{nameof(propertyNameWhitelist)} is specified, but underlying type to register is an open generic.")); } } this.BsonSerializerBuilder = bsonSerializerBuilder; this.PropertyNameWhitelist = propertyNameWhitelist; }
/// <summary> /// Builds a <see cref="TypeToRegister"/> to be used for post-initialization registration, /// which only occurs for closed generic types at serialization-time, because these /// runtime types are not discoverable during initialization. /// </summary> /// <param name="type">The type to register.</param> /// <param name="recursiveOriginType">The type whose recursive processing of <paramref name="memberTypesToInclude"/> and <paramref name="relatedTypesToInclude"/> resulted in the creation of this <see cref="TypeToRegister"/>.</param> /// <param name="directOriginType">The type whose processing of <paramref name="memberTypesToInclude"/> and <paramref name="relatedTypesToInclude"/> directly resulted in the creation of this <see cref="TypeToRegister"/>.</param> /// <param name="memberTypesToInclude">Specifies which member types of <paramref name="type"/> that should also be registered.</param> /// <param name="relatedTypesToInclude">Specifies which types related to <paramref name="type"/> that should also be registered.</param> /// <returns> /// The type to register wrapper. /// </returns> protected abstract TypeToRegister BuildTypeToRegisterForPostInitializationRegistration( Type type, Type recursiveOriginType, Type directOriginType, MemberTypesToInclude memberTypesToInclude, RelatedTypesToInclude relatedTypesToInclude);
/// <summary> /// Initializes a new instance of the <see cref="TypeToRegister{T}"/> class. /// </summary> /// <param name="memberTypesToInclude">Specifies which member types of <typeparamref name="T"/> that should also be registered.</param> /// <param name="relatedTypesToInclude">Specifies which types related to <typeparamref name="T"/> that should also be registered.</param> protected TypeToRegister( MemberTypesToInclude memberTypesToInclude, RelatedTypesToInclude relatedTypesToInclude) : base(typeof(T), memberTypesToInclude, relatedTypesToInclude) { }