当代理被传递到另一个AppDomain时,是否可以将代理编组为代理?

时间:2013-09-09 15:42:59

标签: c# .net delegates appdomain marshalbyrefobject

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

让我们在我的代码中说我有一个类MyClass,如下所示:

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

[Serializable]
public sealed class Input { ... }
[Serializable]
public sealed class Output { ... }

现在我需要将MyClass的实例传递给另一个AppDomain。

问题是存储在SomeDelegate中的委托可能包含对几乎任何方法的引用,包括可能是一个既不是[Serializable]也不是{{1}的类型实例的方法}}

为了这个问题,让我们假设我无法更改创建委托的代码,也不能使MarshalByRefObject成为MyClass。但是,MarshalByRefObject

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

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

1 个答案:

答案 0 :(得分:3)

不幸的是,不能直接使委托本身成为代理。 Delegates are always by-value objects for the purpose of remoting.我发现这是一个奇怪的设计决定,因为我认为它违背了代表的逻辑语义,但这是另一回事。

要解决这个问题,我必须将委托包装到一个我可以创建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;
    }
}

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

[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方法正确签名。