3

不知何故,我假设传递给另一个 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]也不是派生自MarshalByRefObject.

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

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

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

4

1 回答 1

5

Unfortunately it is not directly possible to make the delegate itself a proxy. Delegates are always by-value objects for the purpose of remoting. I find that a strange design decision as I think it goes against the logical semantics of delegates, but that’s another matter.

To solve this, I had to wrap the delegate into a class that I can make a MarshalByRefObject so that it would be proxied. That class needs to have a method that is equivalent to invoking the delegate. To keep this clean, I decided to make that class private:

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;
    }
}

Now I can instantiate this class in the setter of the delegate in 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;
        }
    }
}

This is quite roundabout, but it fulfills all my criteria: The delegate can still be anything; it will be invoked remotely (because it will go through the proxied wrapper); and MyClass is still [Serializable] instead of a proxy.

In theory, one could write an extension method Delegate.ToMarshalByRef() which will do this dynamically with any delegate, but it would have to declare the wrapper class at runtime as it needs an Invoke method with the right signature.

于 2013-09-10T08:51:00.930 回答