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.