Пример #1
0
        /// <summary>
        ///     Create an implementation, or reuse an existing, for an interface.
        ///     Create an instance, add intercepting code, which implements a range of interfaces
        /// </summary>
        /// <param name="interfaceType">Type</param>
        /// <returns>implementation</returns>
        public static IExtensibleInterceptor New(Type interfaceType)
        {
            // create the intercepted object
            if (!interfaceType.IsVisible)
            {
                throw new ArgumentException("Internal types are not allowed.", interfaceType.Name);
            }
            if (!interfaceType.IsInterface)
            {
                throw new ArgumentException("Only interfaces are allowed.", nameof(interfaceType));
            }
            // GetInterfaces doesn't return the type itself, so we need to add it.
            var implementingInterfaces = new[] { interfaceType }.Concat(interfaceType.GetInterfaces()).ToList();

            var implementingAndDefaultInterfaces = new List <Type>();

            foreach (var implementingInterface in implementingInterfaces.ToList())
            {
                implementingAndDefaultInterfaces.Add(implementingInterface);
                if (DefaultInterfacesMap.TryGetValue(implementingInterface, out var defaultInterfaces))
                {
                    implementingAndDefaultInterfaces.AddRange(defaultInterfaces);
                }
            }
            implementingInterfaces = implementingAndDefaultInterfaces.Distinct().ToList();

            // Create an implementation, or lookup
            Type implementingType;

            lock (TypeMap)
            {
                if (!TypeMap.TryGetValue(interfaceType, out implementingType))
                {
                    int typeIndex = 0;
                    // Build a name for the type
                    var typeName = interfaceType.Name + "Impl{0}";
                    // Remove "I" at the start
                    if (typeName.StartsWith("I"))
                    {
                        typeName = typeName.Substring(1);
                    }
                    var fqTypeName = interfaceType.FullName?.Replace(interfaceType.Name, string.Format(typeName, typeIndex));
                    if (fqTypeName == null)
                    {
                        throw new InvalidOperationException($"{interfaceType} doesn't have a name?");
                    }

                    // Only create it if it was not already created via another way
                    while (TypeBuilder.TryGetType(string.Format(fqTypeName, typeIndex), out implementingType))
                    {
                        // Break loop if the types are assignable
                        if (interfaceType.IsAssignableFrom(implementingType))
                        {
                            Log.Verbose().WriteLine("Using cached, probably created elsewhere, type: {0}", fqTypeName);
                            break;
                        }
                        Log.Verbose().WriteLine("Cached type {0} was not compatible with the interface, ignoring.", fqTypeName);
                        fqTypeName = interfaceType.FullName.Replace(interfaceType.Name, string.Format(typeName, typeIndex++));
                    }


                    if (implementingType == null)
                    {
                        // Use this baseType if nothing is specified
                        var baseType = typeof(ExtensibleInterceptorImpl <>);
                        foreach (var implementingInterface in implementingInterfaces)
                        {
                            if (!BaseTypeMap.ContainsKey(implementingInterface))
                            {
                                continue;
                            }
                            baseType = BaseTypeMap[implementingInterface];
                            break;
                        }
                        // Make sure we have a non generic type, by filling in the "blanks"
                        if (baseType.IsGenericType)
                        {
                            baseType = baseType.MakeGenericType(interfaceType);
                        }
                        implementingType = TypeBuilder.CreateType(fqTypeName, implementingInterfaces.ToArray(), baseType);
                    }

                    // Register the implementation for the interface
                    TypeMap[interfaceType] = implementingType;
                }
            }

            if (!interfaceType.IsAssignableFrom(implementingType))
            {
                throw new InvalidOperationException($"{interfaceType.AssemblyQualifiedName} and {implementingType.AssemblyQualifiedName} are not compatible!?");
            }

            // Create an instance for the implementation
            if (!(Activator.CreateInstance(implementingType) is IExtensibleInterceptor interceptor))
            {
                throw new InvalidCastException("Internal error, the created type didn't implement IExtensibleInterceptor.");
            }

            var genericImplementingInterfaces = implementingInterfaces.Where(x => x.IsGenericType).Select(x => x.GetGenericTypeDefinition()).ToList();

            // Add the extensions
            foreach (var extensionType in ExtensionTypes)
            {
                var extensionAttributes = (ExtensionAttribute[])extensionType.GetCustomAttributes(typeof(ExtensionAttribute), false);
                foreach (var extensionAttribute in extensionAttributes)
                {
                    var implementing = extensionAttribute.Implementing;
                    if (implementingInterfaces.Contains(implementing) || genericImplementingInterfaces.Contains(implementing))
                    {
                        interceptor.AddExtension(extensionType);
                    }
                }
            }
            interceptor.Init();
            return(interceptor);
        }