我使用以下方法加载新程序集并在新的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);
。
答案 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);