web-dev-qa-db-ja.com

.NET:実装するインターフェイスにオブジェクトをキャストできません

基本クラス(UserControl)から継承し、インターフェイス(IFrameworkClient)を実装するクラス(TabControlH60)があります。 .NETActivatorクラスを使用してオブジェクトをインスタンス化します。返されたインスタンスを使用して、UserControl基本クラスにキャストできますが、インターフェイスにはキャストできません。私が得る例外は、コードスニペットの下です。インターフェイスにキャストするにはどうすればよいですか?

object obj = Activator.CreateInstance(objType);
Type[] interfaces = obj.GetType().GetInterfaces(); // contains IFrameworkClient

m_Client = (UserControl)obj;                 // base class cast works
IFrameworkClient fc = (IFrameworkClient)obj; // interface cast fails

// Note: The (IFrameworkClient)obj cast works fine in the debugger Watch window.
{"Unable to cast object of type 'FPG.H60.AFF.TabControlH60' to type 
    'FPG.AFF.Interfaces.IFrameworkClient'."}
24
user193327

私のライブラリが「プラグイン」機能を提供しているのと同じ問題が嫌いです...ついに機能しました...

ここに私の問題がありました:プラグインを使用する1つのメインアセンブリ、プラグインを使用する1つのアセンブリ(Plugin.dll)、およびプラグイン機能を提供する(重要な)別のアセンブリ(Library.dll)がありました。

Plugin.dllは、メインアセンブリ(拡張できるようにするため)とLibrary.dllをplugin-funcで参照していました。 -バイナリは、メインアセンブリに関連するディレクトリ「./Plugins」に移動します。

メインアセンブリはplugin-funcも参照していました。 「PluginManager」を使用するためのアセンブリが書き込まれます。この「PluginManager」はパスを取得し、リフレクションを介してすべての* .dllファイルをロードして、「IPlugin」インターフェイス(Library.dllからも取得)があるかどうかを分析します。

プラグインをロードするためにPluginManagerを呼び出すたびに、プラグインは実装されていても「IPlugin」にキャストできませんでした。

私はほとんど怒った-しかしそれから私は全体の問題を見つけた。プラグインをコンパイルすることにより、「Plugin.dll」だけでなく「Library.dll」が「./Plugins」ディレクトリに書き込まれました。 PluginManagerで毎回誤って「Library.dll」をロードすることにより、2種類の「IPlugin」ができました。1つはメインアセンブリから使用される実際の「Library.dll」にあり、もう1つはPluginManagerを介してロードされます。それらは互換性がありませんでした!

注意-「./ Plugins/Library.dll」をロードしないと、それでも問題が発生します-「Library.dll」を参照する「Plugin.dll」をロードすると、同じディレクトリにあるものだけが使用されるためです。 .. TILT ... !!私のPluginManagerは、「Library.dll」を見つけた場所から削除するだけです。

手がかりは次のとおりです。異なるコンテキストで2つのアセンブリにアクセスしないようにしてください。

41
Andi

ここで最も可能性の高い原因は、IFrameworkClientが2つのケースで異なるアセンブリからのものであり、したがって異なる.NETタイプであるということです。同じコードであっても、タイプが異なる場合があります。

AssemblyQualifiedNameを確認してください。このアセンブリをリフレクションでロードしている場合、load-contextのおかげで、異なるタイプを取得できることにも注意してください同じAssemblyQualifiedNameでも

11
Marc Gravell

Interface別のアセンブリ内で、クラスを取得した場合動的別のアセンブリのrun-timeで、interface castingはサンプルのように失敗します(C#は、クラスが継承したものとは異なるタイプとしてインターフェイスを認識します)。

これはこの場合の私のシンプルで便利なテクニックです:

私のClassが前述のInterface(eq。IFrameworkClient)から継承していると確信できる場合は、次のように記述します1つの魔法のコード行この:

dynamic fc = obj as IFrameworkClient ?? (dynamic) obj;

このテクニックを使用すると、次のことができます:

  • design time情報とvsエディターインテリジェンスシステムに基づいてInterface membersfcのこのコード行の後にコードを記述します。
  • run-timeでのインターフェイスキャストエラーを防止します

注:

  • dynamicタイプを使用するには、C# v4が必要です
  • 通常、コードでdynamicタイプを使用するのは好きではありませんが、このような場合に役立ちます。
4
RAM

独立したプロジェクト(クラスライブラリ)の独立した名前空間(名前空間が必要)でIFrameworkClientインターフェイスを定義します。次に、クラスライブラリの参照をコントロールプロジェクトとメインプロジェクトに追加します。

4
SMAH1

何かがあなたのサンプルコードがいくつかのものを省略していることを教えてくれます...

_class Program
{
    static void Main(string[] args)
    {
        var type = typeof(MyClass);
        object obj = Activator.CreateInstance(type);
        Type[] interfaces = obj.GetType().GetInterfaces();

        var m_Client = (UserControl)obj;          
        IFrameworkClient fc = (IFrameworkClient)obj;
    }
}

public interface IFrameworkClient { }

public class UserControl { }

public class MyClass : UserControl, IFrameworkClient { }
_

これはコンパイルされて実行されます。

IFrameworkClientの定義を含むDLLは、キャストを試みる前にまだロードされていません。これは、Activator.CreateInstanceを使用している場合に発生する可能性があります。

キャストの前にvar forceLoad = typeof(IFrameworkClient);を挿入してみてください。

3
user1228

私の場合、インスタンスを作成して実行時にインターフェイスタイプに割り当てていたため、必要なDLLをコピーするためにビルドイベントを追加する必要がありました。それ以外の場合はDLLロードされたDLLは最新のDLLではない可能性があるため、インターフェイスにキャストされない可能性があります。

この場合(DLLを参照として追加する代わりに)ビルドイベントを使用した理由は、メインアプリケーションがインターフェイスタイプのみを参照し、その他はすべて参照する必要があるアーキテクチャであるためです。動的にロードされます。

TLDR;別のDLLから動的に型をロードする場合は、ビルドイベントを使用してそのDLLの最新バージョンをbinディレクトリにコピーしてください。そうしないと、キャストが機能しないように見える場合があります。 。

0
KthProg

同じ問題が発生し、次のコードを追加しました

private void LoadAssemblyPlugins(string dll)

    Assembly ass = AppDomain.CurrentDomain.GetAssemblies()
        .FirstOrDefault(a => new Uri(a.CodeBase).Equals(new Uri(dll)));

   if (ass == null)
       // Load it here
       // use activator here

本番環境では問題になることはありませんが、単体テストでは問題はありましたが、今は再度ロードして「別のタイプ」を作成する必要はありません。

0
T.S.

クラスFPG.H60​​.AFF.TabControlH6が実際にIFrameworkClientを実装している場合、これが失敗する理由はないはずです。この例外の原因となるのは、IFrameworkClientを含むアセンブリに厳密な名前が付けられていて、Tab Controlオブジェクトが含まれているアセンブリの異なるバージョンを参照している場合、またはIFrameworkClientという名前の異なるインターフェイスを使用している場合だけです。

0
Szymon Rozga