如何在不指定assmeblyname的情况下在单独的域上创建类型实例

时间:2013-11-15 17:47:57

标签: c# .net appdomain activator

我的程序包含隐藏在一个可执行文件中的所有DLL。我正在为这个程序开发插件支持。

exe中的所有DLL都作为嵌入式资源存储。以下代码用于访问这些嵌入资源:

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
    var resourceName = Assembly.GetExecutingAssembly()
                        .GetManifestResourceNames()
                        .FirstOrDefault(x => x.EndsWith(new AssemblyName(args.Name).Name + ".dll"));

    using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
    {
        if (stream == null)
            return null; 

        var assemblyData = new byte[stream.Length];
        stream.Read(assemblyData, 0, assemblyData.Length);
        return Assembly.Load(assemblyData);
    }
};

插件在单独的域中加载,以便卸载它们:

public static T CreateInstanceInNewAppDomain<T>(bool shadowCopy = true)
{
    var cdSetupInf = AppDomain.CurrentDomain.SetupInformation;
    var separateDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null,
                                            new AppDomainSetup()
                                            {
                                                LoaderOptimization = LoaderOptimization.MultiDomain,
                                                ApplicationBase = cdSetupInf.ApplicationBase,
                                                PrivateBinPath = cdSetupInf.PrivateBinPath,
                                                ShadowCopyFiles = shadowCopy ? "true" : "false"
                                            }); 

    var type = typeof(T);
    return (T)separateDomain.CreateInstanceFromAndUnwrap(type.Assembly.Location, type.FullName);
}

以前代码中最重要的部分是在单独的域上为创建对象调用“ CreateInstanceFromAndUnwrap ”。如果包含DLL的类型将在HDD上,则这部分代码将很好地工作。由于它是从嵌入式资源加载的,因此assemblyFile参数(表示为type.Assembly.Location)为空。因此,我无法创建我用于访问插件功能的IPluginAccessor实例。有没有什么方法可以在不需要指定assemblyName的情况下在单独的域中创建类型实例?如果有像 AppDomain.CreateInstanceFromAndUnwrap(Type type)这样的东西会很棒。如果我看起来很好,只有 Activator.CreateInstance(类型类型),但这适用于当前域而不是我指定的域。

非常感谢

1 个答案:

答案 0 :(得分:0)

我认为您可以使用将在新AppDomain中执行的Callback。

定义辅助类:

class AnotherAppDomainPluginBuilder<T> : MarshalByRefObject
    where T : new()
{
    T Result { get; set; }

    public void Create()
    {
        LoadRelevantDlls();
        this.Result = new T();
    }

    void LoadRelevantDlls()
    {
        // load whatever DLLs in whatever way you would like to
    }
}

然后代替:

return (T)separateDomain.CreateInstanceFromAndUnwrap(type.Assembly.Location, type.FullName);

写:

AnotherAppDomainPluginBuilder<T> builder =
    (T)separateDomain.CreateInstanceFromAndUnwrap(
        Assembly.CurrentAssembly,
        typeof(AnotherAppDomainPluginBuilder<T> ));

separateDomain.DoCallback(builder.Create);

return builder.Result;