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

标签 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;
}

哪个 get 是这样调用的。

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); 在哪里。

最佳答案

在您的函数 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);

关于c# - Assembly.CreateInstance 返回 null,即使我可以在 DefinedTypes 中看到该类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49488782/

相关文章:

C# 反射 - 加载程序集并调用方法(如果存在)

c# - 是否可以在 C# 类中为多个计时器使用一个异常处理程序?

.net - 我不明白应用程序域

c# - 如何将 ScrollBar 添加到 Stackpanel

c# - 如何访问在运行时定义类型的对象?

c# - 尝试禁用控件时抛出异常

ruby - Ruby 中的反射。通过给定的类名实例化一个对象

c# - 卸载 AppDomain 后,所有程序集都被释放,除了一个

c# - 从类中将项目添加到日志窗口的最佳方法

dependency-injection - 依赖注入(inject)框架 : Why do I care?