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

この質問のために、デリゲートを作成するコードを変更することもMyClassMarshalByRefObject. ただし、[Serializable]です。

(MyClassから派生した型のフィールドが含まれている場合MarshalByRefObject、そのフィールドに格納されているオブジェクトはプロキシに変換され、クラスの残りの部分はシリアル化されることに注意してください。)

クラスをシリアル化されたものとして渡すことができるようにするためにできることはありMarshalByRefObjectますか? (できれば AppDomain のセットアップで変更するMyClass必要がないようにしますが、デリゲートを作成するコードを変更する必要がない限り、クラスの変更を伴う提案も歓迎します。)

4

1 に答える 1

5

残念ながら、デリゲート自体をプロキシにすることは直接できません。デリゲートは、リモート処理のために常に値渡しオブジェクトです。デリゲートの論理セマンティクスに反すると思うので、奇妙な設計上の決定だと思いますが、それは別の問題です。

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

[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

于 2013-09-10T08:51:00.930 に答える