是否可以在将委托传递到另一个应用程序域时将其编组为代理

本文关键字:应用程序域 另一个 代理 是否 | 更新日期: 2023-09-27 18:30:51

不知何故,我假设传递给另一个 AppDomain 的委托会变成代理,就好像它是从MarshalByRefObject派生的对象一样。不幸的是,他们似乎没有。

假设在我的代码中,我有一个这样的类MyClass

[Serializable]
public sealed class MyClass
{
    public Func<Input, Output> SomeDelegate;
}
[Serializable]
public sealed class Input { ... }
[Serializable]
public sealed class Output { ... }

现在,我需要将MyClass实例传递给另一个应用程序域。

问题在于存储在 SomeDelegate 中的委托可能包含对几乎任何方法的引用,包括可能位于既不[Serializable]也不派生自MarshalByRefObject的类型实例上的方法。

为了解决这个问题,让我们假设我不能更改创建委托的代码,也不能使MyClass成为MarshalByRefObject。然而,它[Serializable].

(请注意,如果MyClass包含派生自 MarshalByRefObject 的类型字段,则存储在该字段中的对象将转换为代理,而类的其余部分将被序列化。

能做些什么来允许我以序列化的方式传递类,但将委托变成代理,就像它是MarshalByRefObject一样?(最好是在 AppDomain 的设置中,这样我就不需要更改MyClass,但只要我不需要更改创建委托的代码,也欢迎涉及更改类的建议。

是否可以在将委托传递到另一个应用程序域时将其编组为代理

不幸的是,

不能直接使委托本身成为代理。委托始终是用于远程处理的按值对象。我发现这是一个奇怪的设计决定,因为我认为它违背了代表的逻辑语义,但那是另一回事。

为了解决这个问题,我必须将委托包装到一个类中,我可以对其进行MarshalByRefObject,以便对其进行代理。该类需要具有等效于调用委托的方法。为了保持干净,我决定将该类设为私有:

private sealed class myDelegateWrapper : MarshalByRefObject
{
    public Output Invoke(Input input)
    {
        return _delegate(input);
    }
    private Func<Input, Output> _delegate;
    public myDelegateWrapper(Func<Input, Output> dlgt)
    {
        _delegate = dlgt;
    }
}

现在我可以在委托的 setter 中实例化这个类 MyClass

[Serializable]
public sealed class MyClass
{
    private Func<Input, Output> _someDelegate;
    public Func<Input, Output> SomeDelegate
    {
        get
        {
            return _someDelegate;
        }
        set
        {
            if (value == null)
                _someDelegate = null;
            else
                _someDelegate = new myDelegateWrapper(value).Invoke;
        }
    }
}

这是相当迂回的,但它满足我的所有标准:委托仍然可以是任何东西;它将被远程调用(因为它将通过代理包装器);并且MyClass仍然是[Serializable]而不是代理。

理论上,可以编写一个扩展方法Delegate.ToMarshalByRef()该方法将使用任何委托动态执行此操作,但它必须在运行时声明包装类,因为它需要一个具有正确签名的Invoke方法。