当他们被传递到另一个 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?

将程序集加载到另一个 AppDomain 和类型检查

当传递到另一个对象时,谁应该在 IDisposable 对象上调用 Dispose?

.Net 同一个程序集的两个版本在一个 AppDomain 中加载时是不是存在潜在问题?

将套接字传递给新的 AppDomain

使用 IBAction 将数据传递到另一个视图控制器而无需 segue swift