C# .NET:无法将对象强制转换为其实现的接口

C# .NET:无法将对象强制转换为其实现的接口,c#,interface,casting,base-class,activator,C#,Interface,Casting,Base Class,Activator,我有一个类(TabControlH60),它既继承了基类(UserControl),又实现了接口(IFrameworkClient)。我使用.NET Activator类实例化该对象。对于返回的实例,我可以强制转换到UserControl基类,但不能转换到接口。我得到的例外情况是代码snipet以下。如何向界面强制转换 object obj = Activator.CreateInstance(objType); Type[] interfaces = obj.GetType().GetInte

我有一个类(TabControlH60),它既继承了基类(UserControl),又实现了接口(IFrameworkClient)。我使用.NET Activator类实例化该对象。对于返回的实例,我可以强制转换到UserControl基类,但不能转换到接口。我得到的例外情况是代码snipet以下。如何向界面强制转换

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'."}

强制转换不起作用,因为您正在尝试从类型
对象
强制转换到接口。如果将接口转换线替换为:

IFrameworkClient fc=(IFrameworkClient)m_客户端

它会起作用的

或者,我可以稍微确定您可以使用
as
操作符从对象到接口进行转换

有关更多信息,请参阅本文:

还有一块拼图。接口不是从
对象派生的:

这里最可能的原因是
IFrameworkClient
在这两种情况下来自不同的程序集,因此是不同的.NET类型。即使是相同的代码,也可以是不同的类型


检查
AssemblyQualifiedName
。另外请注意,如果您使用反射加载此程序集,则即使使用相同的AssemblyQualifiedName,也可以获得不同的类型,这要归功于加载上下文。

如果类FPG.H60.AFF.TabControlH60确实实现了IFrameworkClient,则没有任何失败的原因。我能想到的唯一一件导致此异常的事情是,如果包含IFrameworkClient的程序集具有强名称,并且Tab控件对象恰好引用了包含该程序集的不同版本,或者您使用的是名为IFrameworkClient的不同接口。

某种情况告诉我您的示例代码留下了一些错误塞满

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)在转换之前。

在独立项目(类库)的独立名称空间(必须有名称空间)中定义IFrameworkClient接口。然后添加类库的引用以控制项目和主项目

我认为我的库提供“插件”功能也存在同样的问题。。。我终于让它工作了

这就是我的问题:我有一个使用插件的主程序集,一个带有插件(plugin.dll)的程序集,以及(重要的)另一个提供插件功能的程序集(Library.dll)

Plugin.dll引用了主程序集(为了能够扩展它)和带有Plugin func的Library.dll。-它的二进制文件位于相对于主程序集的目录“/Plugins”中

主程序集还引用了插件func。为了使用“PluginManager”而编写的程序集。此“PluginManager”获取路径并通过反射加载所有*.dll文件,以便分析是否存在“IPlugin”接口(也来自Library.dll)

每次我调用PluginManager加载插件时,它都无法将插件强制转换为“IPlugin”,尽管它们实现了它

我差点发疯,但后来我发现了整个问题。通过编译插件,不仅有“plugin.dll”而且还有“Library.dll”被写入“./Plugins”目录。由于每次使用PluginManager时都意外加载“Library.dll”,我现在有两种类型的“IPlugin”——一种是从主程序集中使用的实际“Library.dll”,另一种是通过PluginManager加载的——它们是不兼容的

注意-如果您不加载“/Plugins/Library.dll”,您仍然会遇到问题-因为如果您加载引用“Library.dll”的“Plugin.dll”,那么它只会使用同一目录中的一个。。。倾斜我的PluginManager现在只删除它找到的“Library.dll”


提示是:请确保不要在不同的上下文中访问两个程序集

接口
在另一个程序集中
时,我在另一个程序集中的
运行时动态地获取我的类时,
接口转换
将像您的示例一样失败(C#知道我们的接口是一种不同的类型,而不是类从中继承的类型)

这是我在这种情况下使用的简单实用的技巧:

当我确定我的
继承了前面提到的
接口
(eq.
IFrameworkClient
)时,我就这样写了一行代码:

dynamic fc = obj as IFrameworkClient ?? (dynamic) obj;
通过此技术,您可以:

  • 基于
    接口成员
    信息和vs编辑器智能系统,在
    设计时为
    fc
    的这行代码后编写代码
  • 防止在运行时出现任何接口转换错误
注意事项:

  • 您需要
    C#v4
    才能使用
    dynamic
    类型
  • 通常我不喜欢在代码中使用
    动态
    类型,但在某些情况下它可以帮助我们

在我的例子中,我必须添加一个构建事件来复制所需的DLL,因为我在运行时创建实例并分配给接口类型。否则,加载的DLL可能不是最新的DLL,因此可能不会强制转换到接口

我在本例中使用构建事件(而不是将DLL添加为引用)的原因是,该体系结构使得主应用程序只应引用接口类型,其他所有内容都应动态加载

TLDR; 如果从另一个DLL动态加载类型,请确保使用生成事件将该DLL的最新版本复制到bin目录,否则
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