即使我可以在 DefinedTypes 中看到类,Assembly.CreateInstance 也返回 null [英] Assembly.CreateInstance returning null even though I can see the class in DefinedTypes
问题描述
我使用以下方法加载新程序集并将类的实例创建到新 AppDomain 中.
I use the following method to load a new Assembly and create an instance of a class into a new 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 就是这样调用的.
Which get's called like so.
AppDomain appDomain = AppDomain.CreateDomain(domainName);
appDomainHelper = CreateInstanceFromBinary(appDomain, typeof(MyClass).FullName) as MyClass;
查看 loadedAssembly
我可以看到 MyClass
存在于 DefinedTypes
中,并且它的名称与 typeName
匹配.但是,当代码运行时
Looking into the loadedAssembly
I can see that MyClass
exists inside of the DefinedTypes
and it's name matches typeName
. However, when the code runs
loadedAssembly.CreateInstance(typeName)
它返回空值.
这段代码是有效的,但是,我最近将这个类移动到与调用它相同的 dll 中,现在它已经开始返回 null.
This code was working, however, I recently moved this class into the same dll as the one that calls it and now it has started returning null.
关于如何解决这个问题有什么想法吗?
Any ideas on how to fix this?
对于一些简短的(ish)可重现代码,您可以使用以下代码.在这段代码中,ClassLibrary1
将 CopyLocal 设置为 false,然后作为 EmbeddedResource 包含在我的实时项目中,以防万一.
For some short(ish) reproducible code you can use the following. In this code ClassLibrary1
has CopyLocal set to false and then included as an EmbeddedResource to mimic what I have in my live project in case that matters.
在 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.
Inside of ClassLibrary1
there is 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.
and 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.
Where it is return loadedAssembly.CreateInstance(typeName);
that returns null.
推荐答案
在您的函数 public static HelperClass Create(string domainName)
中,您将 AssemblyQualifiedName 作为要创建的类的类型传递.
In your function public static HelperClass Create(string domainName)
you are passing the AssemblyQualifiedName as the type of the class to create.
我认为你只是想传递类型名称,即:ClassLibrary1.HelperClass
I think you just want to pass the type name, ie: ClassLibrary1.HelperClass
//HelperClass helperClass = CreateInstanceFromBinary(appDomain, typeof(HelperClass).AssemblyQualifiedName) as HelperClass;
HelperClass helperClass = CreateInstanceFromBinary(appDomain, typeof(HelperClass).ToString()) as HelperClass;
我尝试了一些变体,每次传入程序集限定名称失败,只是类型名称按预期工作.
I tried some variations, each time passing in the Assembly Qualified Name failed, just the type name worked as expected.
尝试了各种变体,但失败了:
Variations tried, and failed:
// 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);
这篇关于即使我可以在 DefinedTypes 中看到类,Assembly.CreateInstance 也返回 null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!