0

実行時にタイプ/インターフェイスを知らずに WCF サービスを作成しようとしています。これを行うには、ChannelFactory を使用します。ChannelFactory はジェネリック クラスなので、Type.MakeGenericType を使用する必要があります。MakeGenericType に渡す型は、いくつかのアセンブリを検索して以前にリフレクションで収集したインターフェイスのリストからのものです。

最終的に、MethodInfo.Invoke を呼び出してオブジェクトを作成します。オブジェクトは問題なく作成されますが、適切なインターフェイスにキャストできません。キャストすると、次のエラーが表示されます。

「タイプ 'Tssc.Services.MyType.IMyType' に透過プロキシをキャストできません」

いくつかの実験の後、MakeGenericType に渡されたインターフェイス/型が問題のように思われることがわかりました。リスト内のインターフェイスを実際のインターフェイスに置き換えると、すべて正常に動作します。2 つのオブジェクトをくまなく調べましたが、違いがわかりません。両方の型を生成するようにコードを変更すると、それらを Equals と比較すると false が返されます。Equals が同じオブジェクトを参照していることを確認しているだけなのか (そうでないのか)、それともすべてのプロパティをチェックしているのかなどは不明です。

これは、インターフェイスの収集方法 (リフレクション、リストへの保存など) と関係があるのでしょうか? オブジェクトの比較は、それらが同等であることを示しているようです。両方のオブジェクトのすべてのプロパティを印刷しましたが、それらは同じです。もっと深く掘り下げる必要がありますか?もしそうなら、どこに?

         // createService() method

     //*** tried both of these interfaces, only 2nd works - but they seem to be identical
     //Type t = interfaces[i]; // get type from list created above - doesn't work
     Type t = typeof(Tssc.Services.MyType.IMyType); // actual type - works OK

     // create ChannelFactory type with my type parameter (t)
     Type factoryType = typeof(ChannelFactory<>);
     factoryType = factoryType.MakeGenericType(new Type[] { t });         

     // create ChannelFactory<> object with two-param ctor
     BasicHttpBinding binding = new BasicHttpBinding();
     string address = "blah blah blah";
     var factory = Activator.CreateInstance(factoryType, new object[] { binding, address });

     // get overload of ChannelFactory<>.CreateChannel with no parameters
     MethodInfo method = factoryType.GetMethod("CreateChannel", new Type[] { });

     return method.Invoke(factory, null);

     //--------------- code that calls code above and uses its return

     object ob = createService();

     //*** this cast fails
     Tssc.Services.MyType.IMyType service = (Tssc.Services.MyType.IMyType)ob;
4

1 に答える 1

0

わかりました。ここで何が起こっているのか理解しています。問題は、同じアセンブリを2回ロードすることに関連しています。1回は参照を介して、もう1回はアセンブリのロードコマンドを介してです。アセンブリをロードする場所を変更し、アセンブリが現在のAppDomainにすでに存在するかどうかを確認する必要があります。たとえば、次のようになります。

Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name.Equals("ClassLibrary1Name"));

if (assembly == null)
{
    assembly = System.Reflection.Assembly.LoadFile("path to your assembly");
}

//do your work here

このように、アセンブリがすでにメモリにロードされている場合は、それを使用します。

于 2013-02-20T16:33:56.963 に答える