3

現在、AppDomains を利用するようにプラグイン アーキテクチャを修正しています。私のプラグインと私がオンラインで見つけた多くの例との主な違いは、プラグインが実行されてその結果がメイン アプリケーションに返されるのではなく、私のメイン アプリケーションがプラグインに情報を送信することです。

現状では、ローダーのインスタンスを別の AppDomain に作成します。次に、プラグイン アセンブリの読み込みなど、通常の初期化をすべて行います。この時点で、ローダーのプロキシを使用して、メイン アプリケーションから新しい AppDomain にデータを送信するメソッドを呼び出します。

シリアル化できない引数の型を持ち、MarshalByRefObject から派生していないメソッドを呼び出そうとすると、問題が発生します。

これらのタイプはサードパーティのコードからのものであり、プラグインはそれらを受け取ることを期待しているため、これを行う方法を見つけることができないようです. この質問 ( 「Must be MarshalByRefObject」を C# のような優れた複数継承の切断された言語で解決する方法は? ) を見つけた後、ある種のラッパーを作成することを考えていました。ここでの私の欠点は、サードパーティのコードを変更せずに作成する方法を単純に理解できないことです。

これが私の問題の例です:

// Cant modify this class
class ThirdPartyClass
{
    // The properties are also 3rd party and nonserializable. These are accessed by the plugins.
    public AnotherClass Property1{ get; set; }
    public AnotherClass Property2{ get; set; }

    public ThirdPartyClass(){}
}

class Loader : MarshalByRefObject
{
    private Plugin plugin;

    public Loader()
    {
        Assembly pluginAssembly = Assembly.LoadFrom("Full/Assembly/Path");
        plugin = pluginAssembly.CreateInstance("Full.Plugin.Name") as Plugin;
    }

    public void DoSomething(ThirdPartyClass o)
    {
        ...
        plugin.DoSomethingElse(o);
    }
}

class PluginManager
{
    void Main(ThirdPartyClass o)
    {
        AppDomain pluginAppDomain = AppDomain.CreateDomain("Plugin AppDomain");
        Loader loader = pluginAppDomain.CreateInstanceFromAndUnwrap("Full/Loader/Path", "Full.Loader.Name") as Loader;

        // This is where I would have a problem.
        loader.DoSomething(o);
    }
}

どんな助けでも大歓迎です。

4

2 に答える 2

2

これらがアプリ ドメインの境界を越えている単なるインスタンスである場合、つまり複数のアプリ ドメインで使用しない場合は、MarshalByRefObject から派生したホルダー クラスで単純にラップできます。

IronScheme のリモート処理コードでも同様のアプローチを使用しています。

問題は、インスタンスを保持する以上のことを実際に行う必要がある場合です。この場合、おそらくインターフェイスを使用して必要なメソッドをフックし、「ホルダー」クラスを介してそれを公開できます。

于 2012-06-28T17:37:27.050 に答える
1

appdomain がサード パーティ オブジェクトと対話し、反対側に反映されるようにする必要がありますか? そうでない場合(タイトルに基づいて、シリアライズ可能であってもかまわないように思えます)、シリアライズしないのはなぜですか?つまり、次のようなものです。

[Serializable]
class MyThirdPartyClass : ThirdPartyClass, ISerializable
{
    public MyThirdPartyClass()
    {
    }

    protected MyThirdPartyClass(SerializationInfo info, StreamingContext context)
    {
        Property1 = (AnotherClass)info.GetValue("Property1", typeof(AnotherClass));
        Property2 = (AnotherClass)info.GetValue("Property2", typeof(AnotherClass));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Property1", Property1);
        info.AddValue("Property2", Property2);
    }
}

もちろん、このアプローチには注意点があります。まず、クラスを派生できることに依存し、次に、データを手動で (ある程度) シリアル化する必要があります。内部フィールドのリフレクションを使用して自動化できますが、これは現実的には心配する必要がある唯一のことであり、反対側で再構築して、効果的に手動でシリアル化することができます。

サロゲートセレクターを実装できたかもしれませんが、デフォルトのインターアプリドメインのものを変更することは開発者に公開されていないようです:(

于 2012-06-28T21:00:44.363 に答える