【问题标题】:Assembly.CreateInstance returning null even though I can see the class in DefinedTypes即使我可以在 DefinedTypes 中看到类,Assembly.CreateInstance 返回 null
【发布时间】:2018-03-26 10:03:21
【问题描述】:

我使用下面的方法来加载一个新的程序集并将一个类的实例创建到一个新的 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)

它返回空值。

这段代码可以运行,但是,我最近将这个类移到了调用它的同一个 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;
        }
    }
}

return loadedAssembly.CreateInstance(typeName); 在哪里返回 null。

【问题讨论】:

  • 您是否尝试过使用typeof(MyClass).AssemblyQualifiedName 而不是.FullName?全名通常是不够的。如果没有 AQN,则会有 一些 尝试发现(调用程序程序集或 mscorlib) - 通常在它适用于某些类型但不适用于其他类型时足以引起混淆,但是:它更可靠地工作带有 AQN
  • @MarcGravell 刚刚尝试过,它也返回 null。我刚刚找到this answer,经过更多的环顾,如果您从与我在这里的同一个程序集中调用它会返回null,但它没有证据支持该声明。知道是否真的是这样吗?
  • 对我来说听起来完全是垃圾;我对该帖子添加了评论
  • @MarcGravell 我也是,但是从同一个程序集中调用相同方法与在不同程序集中调用相同方法时显然有些不同。
  • 您创建实例的类是否具有默认构造函数或需要一些参数的构造函数?

标签: c# reflection appdomain


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-24
    • 1970-01-01
    • 2012-11-23
    • 1970-01-01
    • 1970-01-01
    • 2013-10-11
    相关资源
    最近更新 更多