/// <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="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; }
private static CanConvertTypeMatchStrategy ToCanConvertTypeMatchStrategy( this RelatedTypesToInclude relatedTypesToInclude) { CanConvertTypeMatchStrategy result; switch (relatedTypesToInclude) { case RelatedTypesToInclude.None: result = CanConvertTypeMatchStrategy.TypeToConsiderEqualsRegisteredType; break; case RelatedTypesToInclude.Descendants: result = CanConvertTypeMatchStrategy.TypeToConsiderIsAssignableToRegisteredType; break; case RelatedTypesToInclude.Ancestors: result = CanConvertTypeMatchStrategy.TypeToConsiderIsAssignableFromRegisteredType; break; case RelatedTypesToInclude.AncestorsAndDescendants: result = CanConvertTypeMatchStrategy.TypeToConsiderIsAssignableToOrFromRegisteredType; break; default: throw new NotSupportedException(Invariant($"This {nameof(RelatedTypesToInclude)} is not supported: {relatedTypesToInclude}.")); } return(result); }
/// <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="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> GetRelatedTypesToInclude( Type type, RelatedTypesToInclude relatedTypesToInclude) { // 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; relatedTypesToInclude = relatedTypesToInclude == RelatedTypesToInclude.Default ? type.ResolveDefaultIntoActionableRelatedTypesToInclude() : relatedTypesToInclude; if (relatedTypesToInclude == RelatedTypesToInclude.None) { return(new Type[0]); } // Short-circuit restricted types. We will see these types here because we want to explore them in // GetMemberTypesToInclude (e.g. List<MyModel>), but we are not interested in their related types // (e.g. IEnumerable). if (IsRestrictedType(type)) { return(new Type[0]); } // In a past iteration of this code we checked type.IsAssignableFrom against all loaded types, and vice versa. // In that iteration we purposefully avoided TypeHelper.IsAssignableTo because of performance issues related // to the OBeautifulCode.Validation calls in that method. Also, IsAssignableTo throws when parameter 'type' // is a generic type definition. // Unfortunately, IsAssignableFrom is not a complete solution for generic types. // For generic types, IsAssignableFrom sometimes find ancestors but not always, depending on how // the type's inheritance is structured/declared. Consider: // class Parent<T> { } // class Child<T> : Parent<T> { } // typeof(Child<>).BaseType != typeof(Parent<>) // typeof(Parent<>).IsAssignableFrom(typeof(Child<>)) == false // typeof(Child<>).BaseType is actually not a loaded type. So this "related type" relationship cannot be discovered // using the methodology of the prior iteration of this code. DiscoverAncestorsAndDescendants(type); IReadOnlyCollection <Type> result; switch (relatedTypesToInclude) { // note we don't need to check whether TypeToAncestorTypesMap or TypeToAncestorTypesMap contains type // because type is guaranteed to be keys in those dictionaries after the call to DiscoverAncestorsAndDescendants() above case RelatedTypesToInclude.Ancestors: result = TypeToAncestorTypesMap[type].ToList(); break; case RelatedTypesToInclude.Descendants: result = TypeToDescendantTypesMap[type].ToList(); break; case RelatedTypesToInclude.AncestorsAndDescendants: result = new Type[0].Concat(TypeToAncestorTypesMap[type]).Concat(TypeToDescendantTypesMap[type]).ToList(); break; default: throw new NotSupportedException(Invariant($"This {nameof(RelatedTypesToInclude)} is not supported: {relatedTypesToInclude}")); } // 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 = result .Concat(genericTypeDefinitions) .ToList(); 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) { }