0

私は動的に(mefを使用して)ロードするクラスを持っています。それらはある種のハンドラです(これらは正常に動作します)。

これらのハンドラーは (パケットを受信して​​ 1 つを返すメソッドがあります) パケットを受け取ることができ、それらはすべて同じインターフェイス (たとえば IPacket としましょう) を実装し、応答 (IPacket も) を返します。

私はこれらのパケットを (tcp 接続を介して) 受信しましたが、私のプログラムは特定のクラスに精通していません (ただし、既知のインターフェイス - IPacket ですが、実装は異なります)。

そのため、(ハンドラーに渡すために) パケットを逆シリアル化しようとすると、例外が発生します。

  • バイトにシリアル化し、オブジェクトに逆シリアル化します (バイナリ シリアライザーを使用) *

dll はアクセス可能なフォルダーに格納されているため、パケットの実装にアクセスできる唯一の方法は動的でなければなりません。

私は、プログラムをパケットに慣れさせるために Assembly.LoadFrom を使用するだけでよいと考えました。パケットをインスタンス化する必要さえなく、逆シリアル化 (インターフェイスのインスタンスを取得) してハンドラーに渡すだけです。その後、回答が返され、もう一度送信します。

しかし、それはうまくいきませんでした..

実行時にこれらの dll への参照を追加する方法を見つける必要があると仮定すると、私のプログラムはそれらを認識します.. (パック クラスで Export(typeof()..) を使用すると役立つと思います。それ?)

逆シリアル化しようとすると発生する例外は、クラス名が見つからないことです..

*トピックを編集しました。もう少し明確になることを願っています。ありがとう =]


  • 編集:

これが mef で解決できると言っているわけではありません。それは間違いなくリフレクションで解決できます。実行時にプログラムに認識させたいすべてのクラスを含むフォルダーがあります。同じフォルダー内のdllへの参照を追加したかのように、実行時にクラスを「ロード」するだけです。

だから基本的に私がする必要があるのは:

特定のインターフェイス (この例では IPacket) のすべての実装をフォルダーから読み込みます。それらをインスタンス化する必要はありませんが、そのような型がプロジェクトにないという例外を取得せずに変数として受け取るだけです。


だから私はこのスニペットを見つけました:

static constructor() {
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

}

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
    Assembly ayResult = null;
    string sShortAssemblyName = args.Name.Split(',')[0];
     Assembly[] ayAssemblies = AppDomain.CurrentDomain.GetAssemblies();
     foreach (Assembly ayAssembly in ayAssemblies) {
        if (sShortAssemblyName == ayAssembly.FullName.Split(',')[0]) {
             ayResult = ayAssembly;
             break;
        }
     }
     return ayResult;
}

私が探しているものに近いようですが、実際にはこれを理解していません。特定のフォルダー内の dll のみをロードするようにこれを修正する方法はありますか? 私のプログラムはdllに慣れていますか?

また、コードの説明は大歓迎です。

4

2 に答える 2

1

MEF は間違いなく役に立ちますが、それだけではありません。ISerializationSurrogateを使用する必要があります。以下の説明のほとんどは、ここにあります

したがって、パケット インターフェイスの次の定義が与えられます。

public interface IPacket
{
    string GetInfo();
}

独自のアセンブリに存在する次の実装があります。

[Export(typeof(IPacket))]
class FirstPacket : IPacket
{
    public FirstPacket()
    {
        Name = "Joe";
    }

    public string Name { get; set; }

    public string GetInfo()
    {
        return "Name: " + Name;
    }
}

[Export(typeof(IPacket))]
class SecondPacket : IPacket
{
    public SecondPacket()
    {
        Measurement = 42.42m;
    }

    public decimal Measurement { get; set; }

    public string GetInfo()
    {
        return "Measurement: " + Measurement;
    }
}

次に、次のような別のインターフェイスを定義します。

public interface IPacketSurrogateProvider
{
    void AddSurrogate(SurrogateSelector toSelector);
}

そして、具体的なパケットが定義されている同じアセンブリ内の一致する実装:

[Export(typeof(IPacketSurrogateProvider))]
class FirstPacketSurrogateProvider : IPacketSurrogateProvider, ISerializationSurrogate
{
    public void AddSurrogate(SurrogateSelector toSelector)
    {
        toSelector.AddSurrogate(typeof(FirstPacket), new StreamingContext(StreamingContextStates.All), this);
    }

    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Name", ((FirstPacket)obj).Name);
    }

    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {
        ((FirstPacket)obj).Name = info.GetString("Name");

        return obj;
    }
}

[Export(typeof(IPacketSurrogateProvider))]
class SecondPacketSurrogateProvider : IPacketSurrogateProvider, ISerializationSurrogate
{
    public void AddSurrogate(SurrogateSelector toSelector)
    {
        toSelector.AddSurrogate(typeof(SecondPacket), new StreamingContext(StreamingContextStates.All), this);
    }

    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Measurement", ((SecondPacket)obj).Measurement);
    }

    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {
        ((SecondPacket)obj).Measurement = info.GetDecimal("Measurement");

        return obj;
    }
}

そして今、インターフェイスを持つものへの参照を持ち、実装を持つものへの参照を持たず、上記の両方と同じ展開フォルダーを持つアセンブリで:

public static void Test()
{
    var container = new CompositionContainer(new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)));

    var packets = container.GetExportedValues<IPacket>().ToArray();
    var packetSurrogateProviders = container.GetExportedValues<IPacketSurrogateProvider>();

    var surrogateSelector = new SurrogateSelector();
    foreach (var provider in packetSurrogateProviders)
    {
        provider.AddSurrogate(surrogateSelector);
    }

    var deserializedPackets = new IPacket[] { };
    using (var stream = new MemoryStream())
    {
        var formatter = new BinaryFormatter {SurrogateSelector = surrogateSelector};

        formatter.Serialize(stream, packets);

        stream.Position = 0;

        deserializedPackets = (IPacket[])formatter.Deserialize(stream);
    }

    foreach (var packet in deserializedPackets)
    {
        Console.WriteLine("Packet info: {0}", packet.GetInfo());
    }
}

生成するもの:

パケット情報: 名前: ジョー

パケット情報: 測定値: 42.42

于 2013-10-18T00:19:02.763 に答える