如何创建应用程序域并在其中运行我的应用程序?

23

我需要创建一个自定义应用程序域来解决 .NET 运行时的 默认行为 中的一个错误。在线上看到的所有示例代码都不太有用,因为我不知道它应该放在哪里,或者需要替换我的 Main() 方法中的什么内容。

2个回答

42

需要注意的是,仅仅为了解决可以通过常量字符串修复的问题而创建 AppDomains 可能不是正确的做法。如果您想要实现与您所提到的链接相同的功能,您可以这样做:

var configFile = Assembly.GetExecutingAssembly().Location + ".config";
if (!File.Exists(configFile))
    throw new Exception("do your worst!");

递归入口点 :o)

static void Main(string[] args)
{
    if (AppDomain.CurrentDomain.IsDefaultAppDomain())
    {
        Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);

        var currentAssembly = Assembly.GetExecutingAssembly();
        var otherDomain = AppDomain.CreateDomain("other domain");
        var ret = otherDomain.ExecuteAssemblyByName(currentAssembly.FullName, args);

        Environment.ExitCode = ret;
        return;
    }

    Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
    Console.WriteLine("Hello");
}

使用非静态的次要入口点和MarshalByRefObject进行快速示例...

class Program
{
    static AppDomain otherDomain;

    static void Main(string[] args)
    {
        otherDomain = AppDomain.CreateDomain("other domain");

        var otherType = typeof(OtherProgram);
        var obj = otherDomain.CreateInstanceAndUnwrap(
                                 otherType.Assembly.FullName,
                                 otherType.FullName) as OtherProgram;

        args = new[] { "hello", "world" };
        Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
        obj.Main(args);
    }
}

public class OtherProgram : MarshalByRefObject
{
    public void Main(string[] args)
    {
        Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
        foreach (var item in args)
            Console.WriteLine(item);
    }
}

1
谢谢。有没有任何理由偏爱一种方法而不是另一种? - Dan Is Fiddling By Firelight
1
还有一个 AppDomain 对象上的 .ExecuteAssembly(...) 方法,您可以提供包含入口点的另一个程序集的路径。 这可能会带来稍微更干净的设计,但至少需要两个程序集。 - Matthew Whited
1
我知道这一定是可能的... 诀窍在于找出如何在不引用 mscoree.tlb 的情况下完成它。 - Matthew Whited
1
我不知道。 - Matthew Whited
看起来它取决于运行时的版本而不是操作系统。 - Matthew Whited
显示剩余7条评论

6
您需要:
1)创建一个AppDomainSetup对象的实例,并填充您想要的域的设置信息
2)使用AppDomain.CreateDomain方法创建您的新域。将带有配置参数的AppDomainSetup实例传递给CreateDomain方法。
3)通过在域对象上使用CreateInstanceAndUnwrap方法,创建新域中对象的实例。此方法需要您要创建的对象的类型名称,并返回一个远程代理,您可以在主域中使用该代理与在新域中创建的对象通信。
完成这3个步骤后,您可以通过代理调用其他域中的方法。您也可以在完成后卸载域并重新加载它。
此MSDN帮助中的topic具有非常详细的示例。

2
这大概就是我在其他地方看到的例子,但是它并没有提供我仍然缺少的任何信息。我只需要调用Application.Run(new MyForm)吗?我是将所有现有的启动代码从我的Main方法中删除,并将其放入一个新方法中,然后调用它来启动我的应用程序吗?以上都不是,因为我比我想象中更困惑? - Dan Is Fiddling By Firelight
1
你正在尝试获取代理的对象必须是MarshalByRefObject,否则它将只尝试将副本序列化回原始的AppDomain。 - Matthew Whited
1
@Dan 我从未尝试在非主域中运行与UI相关的内容。就UI而言,我担心你会遇到一些麻烦,主要是因为它基于旧的非托管代码。如果你感觉胆大,可以尝试将整个东西推到次要域并查看它的工作情况。我的意思是在次要域中实例化Application类并调用Run方法。 - mfeingold
1
Matthew Whited建议的递归入口方法在没有任何GUI问题的情况下工作。 - Dan Is Fiddling By Firelight

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接