Is it possible to have delegates marshalled as proxies when they are passed across to another AppDomain?

时间秒杀一切 提交于 2019-12-10 11:24:34

问题


Somehow I assumed that delegates passed to another AppDomain would turn into a proxy as if it were an object derived from MarshalByRefObject. Unfortunately, it seems they don’t.

Let’s say in my code I have a class MyClass like this:

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

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

Now I need to pass an instance of MyClass to another AppDomain.

The problem is that the delegate stored in SomeDelegate may contain a reference to pretty much any method, including potentially a method on an instance of a type that is neither [Serializable] nor derived from MarshalByRefObject.

For the sake of this question, let’s assume that I cannot change the code that creates the delegate, nor can I make MyClass a MarshalByRefObject. It is, however, [Serializable].

(Note that if MyClass contained a field of a type that derives from MarshalByRefObject, the object stored in that field would be turned into a proxy, while the rest of the class is serialized.)

Is there something I can do that will allow me to pass the class as serialized, but with the delegate turned into a proxy, just as it would be if it were a MarshalByRefObject? (Preferably in the setup of the AppDomain so that I don’t need to change MyClass, but suggestions that involve changing the class are welcome too as long as I don’t need to change the code that creates the delegate.)


回答1:


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.



来源:https://stackoverflow.com/questions/18702041/is-it-possible-to-have-delegates-marshalled-as-proxies-when-they-are-passed-acro

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!