当他们被传递到另一个 AppDomain 时,是不是可以将代表编组为代理?
Posted
技术标签:
【中文标题】当他们被传递到另一个 AppDomain 时,是不是可以将代表编组为代理?【英文标题】:Is it possible to have delegates marshalled as proxies when they are passed across to another AppDomain?当他们被传递到另一个 AppDomain 时,是否可以将代表编组为代理? 【发布时间】:2013-09-09 15:42:59 【问题描述】:不知何故,我假设传递给另一个 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
,但是只要我不需要更改创建委托的代码,也欢迎涉及更改类的建议。)
【问题讨论】:
理论上,您可以创建一个 AOP 包装器,在远程端将数据序列化到托管 AppDomain 并运行委托。有点复杂...您可以查看 Windsor Castle 的 DynamicProxy 或 Unity 的 Interceptor 来执行此操作... 【参考方案1】:不幸的是,不能直接将委托本身设置为代理。 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
方法。
【讨论】:
以上是关于当他们被传递到另一个 AppDomain 时,是不是可以将代表编组为代理?的主要内容,如果未能解决你的问题,请参考以下文章
AppDomain 和 MarshalByRefObject 生命周期:如何避免 RemotingException?
当传递到另一个对象时,谁应该在 IDisposable 对象上调用 Dispose?