internal Tuple <GeneratedImplementationTypeIdentifier, Type> PregenerateImplementationType
        (
            [NotNull] Type classType,
            [NotNull] params Type[] interfaceTypes
        )
        {
            if (!classType.IsAbstract)
            {
                throw new ArgumentException
                      (
                          "The class to activate must be abstract.",
                          nameof(classType)
                      );
            }

            if (!(classType.IsSubclassOf(typeof(NativeLibraryBase)) || classType == typeof(NativeLibraryBase)))
            {
                throw new ArgumentException
                      (
                          $"The base class must be or derive from {nameof(NativeLibraryBase)}.",
                          nameof(classType)
                      );
            }

            if (!interfaceTypes.Any(i => i.IsInterface))
            {
                throw new ArgumentException
                      (
                          "The interfaces to activate on the class must be an interface type.",
                          nameof(interfaceTypes)
                      );
            }

            // Check if we've already generated a type for this configuration
            var  key = new GeneratedImplementationTypeIdentifier(classType, interfaceTypes, Options);
            Type generatedType;

            lock (BuilderLock)
            {
                if (TypeCache.TryGetValue(key, out generatedType))
                {
                    return(new Tuple <GeneratedImplementationTypeIdentifier, Type>(key, generatedType));
                }

                generatedType = GenerateInterfaceImplementationType(classType, interfaceTypes);
                TypeCache.TryAdd(key, generatedType);
            }

            return(new Tuple <GeneratedImplementationTypeIdentifier, Type>(key, generatedType));
        }
        /// <summary>
        /// Generates the implementation type for a given class and interface combination, caching it for later use.
        /// </summary>
        /// <typeparam name="TBaseClass">The base class for the implementation to generate.</typeparam>
        /// <typeparam name="TInterface">The interface to implement.</typeparam>
        /// <exception cref="ArgumentException">Thrown if either of the type arguments are incompatible.</exception>
        /// <exception cref="FileNotFoundException">
        /// Thrown if the specified library can't be found in any of the loader paths.
        /// </exception>
        internal void PregenerateImplementationType <TBaseClass, TInterface>()
            where TBaseClass : NativeLibraryBase
            where TInterface : class
        {
            var classType = typeof(TBaseClass);

            if (!classType.IsAbstract)
            {
                throw new ArgumentException
                      (
                          "The class to activate must be abstract.",
                          nameof(TBaseClass)
                      );
            }

            var interfaceType = typeof(TInterface);

            if (!interfaceType.IsInterface)
            {
                throw new ArgumentException
                      (
                          "The interface to activate on the class must be an interface type.",
                          nameof(TInterface)
                      );
            }

            // Check if we've already generated a type for this configuration
            var key = new GeneratedImplementationTypeIdentifier(classType, interfaceType, Options);

            lock (BuilderLock)
            {
                if (TypeCache.TryGetValue(key, out var generatedType))
                {
                    return;
                }

                generatedType = GenerateInterfaceImplementationType <TBaseClass, TInterface>();
                TypeCache.TryAdd(key, generatedType);
            }
        }
Example #3
0
        public TClass ActivateClass <TClass, TInterface>([NotNull] string libraryPath)
            where TClass : NativeLibraryBase
            where TInterface : class
        {
            var classType = typeof(TClass);

            if (!classType.IsAbstract)
            {
                throw new ArgumentException("The class to activate must be abstract.", nameof(TClass));
            }

            var interfaceType = typeof(TInterface);

            if (!interfaceType.IsInterface)
            {
                throw new ArgumentException
                      (
                          "The interface to activate on the class must be an interface type.",
                          nameof(TInterface)
                      );
            }

            // Check for remapping
            if (Options.HasFlagFast(EnableDllMapSupport))
            {
                libraryPath = new DllMapResolver().MapLibraryName(interfaceType, libraryPath);
            }

            // Attempt to resolve a name or path for the given library
            var resolveResult = PathResolver.Resolve(libraryPath);

            if (!resolveResult.IsSuccess)
            {
                throw new FileNotFoundException
                      (
                          $"The specified library (\"{libraryPath}\") was not found in any of the loader search paths.",
                          libraryPath,
                          resolveResult.Exception
                      );
            }

            libraryPath = resolveResult.Path;

            // Check if we've already generated a type for this configuration
            var key = new GeneratedImplementationTypeIdentifier(classType, interfaceType, libraryPath, Options);

            if (!TypeCache.TryGetValue(key, out var generatedType))
            {
                lock (BuilderLock)
                {
                    generatedType = GenerateInterfaceImplementationType <TClass, TInterface>();
                    TypeCache.TryAdd(key, generatedType);
                }
            }

            try
            {
                var anonymousInstance = CreateAnonymousImplementationInstance <TInterface>
                                        (
                    generatedType,
                    libraryPath,
                    Options,
                    TransformerRepository
                                        );

                return(anonymousInstance as TClass
                       ?? throw new InvalidOperationException
                       (
                           "The resulting instance was not convertible to an instance of the class."
                       ));
            }
            catch (TargetInvocationException tex)
            {
                if (tex.InnerException is null)
                {
                    throw;
                }

                // Unwrap target invocation exceptions, since we can fail in the constructor
                throw tex.InnerException;
            }
        }
        public object ActivateClass
        (
            [NotNull] string libraryPath, [NotNull] Type baseClassType, [NotNull] params Type[] interfaceTypes
        )
        {
            if (!baseClassType.IsAbstract)
            {
                throw new ArgumentException("The class to activate must be abstract.", nameof(baseClassType));
            }

            if (!interfaceTypes.Any(i => i.IsInterface))
            {
                throw new ArgumentException
                      (
                          "The interfaces to activate on the class must be an interface type.",
                          nameof(interfaceTypes)
                      );
            }

            // Attempt to resolve a name or path for the given library
            var resolveResult = PathResolver.Resolve(libraryPath);

            if (!resolveResult.IsSuccess)
            {
                throw new FileNotFoundException
                      (
                          $"The specified library (\"{libraryPath}\") was not found in any of the loader search paths.",
                          libraryPath,
                          resolveResult.Exception
                      );
            }

            libraryPath = resolveResult.Path;

            // Check if we've already generated a type for this configuration
            var key = new GeneratedImplementationTypeIdentifier(baseClassType, interfaceTypes, Options);

            lock (BuilderLock)
            {
                if (!TypeCache.TryGetValue(key, out var generatedType))
                {
                    generatedType = GenerateInterfaceImplementationType(baseClassType, interfaceTypes);
                    TypeCache.TryAdd(key, generatedType);
                }

                try
                {
                    var anonymousInstance = CreateAnonymousImplementationInstance
                                            (
                        generatedType,
                        libraryPath,
                        Options
                                            );

                    return(anonymousInstance);
                }
                catch (TargetInvocationException tex)
                {
                    if (tex.InnerException is null)
                    {
                        throw;
                    }

                    // Unwrap target invocation exceptions, since we can fail in the constructor
                    throw tex.InnerException;
                }
            }
        }