/// <summary> /// Build the entire type tree and type cache /// </summary> private void BuildTypeTree() { // Start with all public types var allTypes = new List <Type>(); var registeredTypes = Container.GetRegisteredImplementations(typeof(IResource)).ToList(); // Load full type tree from registered resources foreach (var type in registeredTypes.Union(ReflectionTool.GetPublicClasses <Resource>())) { var buffer = type; // Exclude the different base types from "Moryx.Resources" from the type tree do { if (buffer.IsGenericType) // Generic base types appear multiple times, use only the generic type { buffer = buffer.GetGenericTypeDefinition(); } if (!allTypes.Contains(buffer)) { allTypes.Add(buffer); } buffer = buffer.BaseType; } while (buffer != null && buffer != typeof(Resource)); } // Convert tree to TypeNodes objects RootType = Convert(typeof(Resource), allTypes, registeredTypes); }
/// <summary> /// Get all interfaces of a linker that are relevant for the public proxy. This excludes all non-public /// interfaces or interfaces that are not derived from IPublicResource. /// </summary> private static IReadOnlyList <Type> RelevantInterfaces(ResourceTypeNode node) { var interfaces = node.ResourceType.GetInterfaces(); var relevantInterfaces = new List <Type>(interfaces.Length); // At max all interfaces are relevant // Load additional public interfaces from resource registration attribute var additionalPublicInterfaces = node.ResourceType.GetCustomAttributes <ResourceAvailableAsAttribute>() .SelectMany(a => a.AvailableAs).Distinct(); // Add all resources derived from IResource, but not IResource itself relevantInterfaces.AddRange(from resourceInterface in interfaces where resourceInterface.IsPublic && ((typeof(IResource).IsAssignableFrom(resourceInterface) && !resourceInterface.IsAssignableFrom(typeof(IResource))) || additionalPublicInterfaces.Contains(resourceInterface)) select resourceInterface); // Add all interfaces that are NOT derived from IResource BUT part of any of the relevant interfaces relevantInterfaces.AddRange(from generalInterface in interfaces where !generalInterface.IsAssignableFrom(typeof(IResource)) && // It should not be a base type if IResource !relevantInterfaces.Contains(generalInterface) && // It should not be part of the relevant interfaces yet relevantInterfaces.Any(generalInterface.IsAssignableFrom) // It is a base type of a relevant interface select generalInterface); return(relevantInterfaces); }
private ResourceTypeNode Convert(Type type, ICollection <Type> allTypes, ICollection <Type> registeredTypes, ResourceTypeNode baseType = null) { // Create linker from type var linker = new ResourceTypeNode { ResourceType = type, BaseType = baseType, IsRegistered = registeredTypes.Contains(type), Constructors = (from method in type.GetMethods() let att = method.GetCustomAttribute <ResourceConstructorAttribute>() where att != null orderby att.IsDefault descending select method).ToArray() }; // Find all derived types // ReSharper disable once PossibleNullReferenceException -> There is always a base type var derived = allTypes.Where(t => (t.BaseType.IsGenericType ? t.BaseType.GetGenericTypeDefinition() : t.BaseType) == type); linker.DerivedTypes = derived.Select(t => Convert(t, allTypes, registeredTypes, linker)).ToArray(); // Save reference in type cache _typeCache[linker.Name] = linker; return(linker); }
/// <summary> /// Recursively check if any type in the tree supports the referenced type /// </summary> /// <param name="type">Current node in the recursive call</param> /// <param name="typeConstraints">All type constraints a candidate needs to match to be compatible</param> /// <param name="supportedTypes">Current list of supported types</param> private static void SupportingType(ResourceTypeNode type, ICollection <Type> typeConstraints, ICollection <ResourceTypeNode> supportedTypes) { // This type supports the property -> Convert it and break recursion if (typeConstraints.All(tc => tc.IsAssignableFrom(type.ResourceType))) { supportedTypes.Add(type); return; } // Otherwise check its derived types foreach (var derivedType in type.DerivedTypes) { SupportingType(derivedType, typeConstraints, supportedTypes); } }