Assembly.CreateInstance返回null,即使我可以在DefinedTypes中看到该类

时间:2018-03-26 10:03:22

标签: c# reflection appdomain

我使用以下方法加载新程序集并在新的AppDomain中创建类的实例。

private static object CreateInstanceFromBinary(AppDomain appDomain, string typeName)
{
    Assembly entryAssembly = Assembly.GetEntryAssembly();

    byte[] assemblyBinary = LoadAssemblyBinary();

    Assembly loadedAssembly = appDomain.Load(assemblyBinary);
    if (loadedAssembly != null)
    {
        return loadedAssembly.CreateInstance(typeName);
    }

    return null;
}

这样被称为。

AppDomain appDomain = AppDomain.CreateDomain(domainName);

appDomainHelper = CreateInstanceFromBinary(appDomain, typeof(MyClass).FullName) as MyClass;

查看loadedAssembly我可以看到MyClass中存在DefinedTypes,其名称与typeName匹配。但是,代码运行时

loadedAssembly.CreateInstance(typeName)

它返回null。

这段代码正在运行,但是,我最近将这个类移动到与调用它的同一个dll中,现在它已经开始返回null。

有关如何解决此问题的任何想法?

对于某些简短(ish)可重现的代码,您可以使用以下代码。在此代码中,ClassLibrary1将CopyLocal设置为false,然后将其作为EmbeddedResource包含在内,以模仿我在实时项目中的内容,以防万一。

ConsoleApplication1内部我有程序。

using ClassLibrary1;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static Program()
        {
            AppDomain.CurrentDomain.AssemblyResolve += Resolve;
        }

        static void Main(string[] args)
        {
            WorkerClass workerClass = new WorkerClass();
            workerClass.DoWork();

            Console.WriteLine("\r\nPress enter to exit...");
            Console.ReadLine();
        }

        static System.Reflection.Assembly Resolve(object sender, ResolveEventArgs args)
        {
            if (!args.Name.Contains(","))
            {
                return null;
            }

            List<string> rn = System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceNames()
                                                                           .Where(r => r.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
                                                                           .ToList();

            string assemblyName = rn.FirstOrDefault(r => r.EndsWith(args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll"));
            if (!String.IsNullOrEmpty(assemblyName))
            {
                using (Stream stream = System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream(assemblyName))
                {
                    byte[] assemblyBinary = new byte[stream.Length];
                    stream.Read(assemblyBinary, 0, assemblyBinary.Length);

                    System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(assemblyBinary);

                    if (Environment.UserInteractive)
                    {
                        Console.WriteLine("Loaded Assembly: " + assembly.FullName);
                    }

                    return assembly;
                }
            }

            if (Environment.UserInteractive)
            {
                Console.WriteLine($"** Failed to find an assembly with name: {args.Name} ** ");
            }

            return null;
        }
    }
}

ClassLibrary1内部有WorkerClass。

using System;

namespace ClassLibrary1
{
    public class WorkerClass
    {
        public void DoWork()
        {
            try
            {
                HelperClass hc = HelperClass.Create("Name");
                Console.WriteLine("Created");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed to create: " + ex.ToString());
            }
        }
    }
}

和HelperClass。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Permissions;

namespace ClassLibrary1
{
    [Serializable]
    public class HelperClass : MarshalByRefObject
    {
        public AppDomain Domain { get; private set; }

        public HelperClass()
        {

        }

        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
        public override object InitializeLifetimeService()
        {
            return null;
        }

        public static HelperClass Create(string domainName)
        {
            AppDomain appDomain = AppDomain.CreateDomain(domainName);

            HelperClass helperClass = CreateInstanceFromBinary(appDomain, typeof(HelperClass).AssemblyQualifiedName) as HelperClass;
            if (helperClass == null)
            {
                throw new Exception("Unable to create instance from binary resource.");
            }

            helperClass.Domain = appDomain;

            return helperClass;
        }

        private static object CreateInstanceFromBinary(AppDomain appDomain, string typeName)
        {
            Assembly entryAssembly = Assembly.GetEntryAssembly();

            IList<string> rn = entryAssembly.GetManifestResourceNames().Where(r => r.EndsWith(".dll")).ToList();

            string assembly = rn.FirstOrDefault(r => r.EndsWith($"{typeof(HelperClass).Assembly.GetName().Name}.dll"));
            if (!String.IsNullOrEmpty(assembly))
            {
                using (Stream stream = entryAssembly.GetManifestResourceStream(assembly))
                {
                    byte[] assemblyBinary = new byte[stream.Length];
                    stream.Read(assemblyBinary, 0, assemblyBinary.Length);

                    Assembly loadedAssembly = appDomain.Load(assemblyBinary);
                    if (loadedAssembly != null)
                    {
                        return loadedAssembly.CreateInstance(typeName);
                    }
                }
            }

            return null;
        }
    }
}

返回null的return loadedAssembly.CreateInstance(typeName);

1 个答案:

答案 0 :(得分:0)

在函数public static HelperClass Create(string domainName)中,您将AssemblyQualifiedName作为要创建的类的类型传递。

我认为您只想传递类型名称,即:ClassLibrary1.HelperClass

//HelperClass helperClass = CreateInstanceFromBinary(appDomain, typeof(HelperClass).AssemblyQualifiedName) as HelperClass;
HelperClass helperClass = CreateInstanceFromBinary(appDomain, typeof(HelperClass).ToString()) as HelperClass;

我尝试了一些变体,每次传递程序集合格名称失败时,只是类型名称按预期工作。

尝试变种,但失败了:

 // Do not work
 var x = loadedAssembly.CreateInstance(typeName); //AssemblyQualifiedName
 var loadedType = loadedAssembly.GetType(typeName); //AssemblyQualifiedName

 // Work
 var x = Activator.CreateInstance(typeof(HelperClass)); // Works
 var x = loadedAssembly.CreateInstance("ClassLibrary1.HelperClass");

 var loadedType = loadedAssembly.GetType("ClassLibrary1.HelperClass");
 var x = Activator.CreateInstance(loadedType);