.NET:无法将对象转换为它实现的接口

Posted

技术标签:

【中文标题】.NET:无法将对象转换为它实现的接口【英文标题】:.NET: Unable to cast object to interface it implements 【发布时间】:2010-12-08 11:34:27 【问题描述】:

我有一个类 (TabControlH60),它既继承自基类 (UserControl),又实现了接口 (IFrameworkClient)。我使用 .NET Activator 类实例化对象。使用返回的实例,我可以转换为 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'."

【问题讨论】:

【参考方案1】:

转换不起作用,因为您试图从类型 object 转换到接口。如果将接口转换线替换为:

IFrameworkClient fc = (IFrameworkClient)m_Client;

它会起作用的。

或者,我可以肯定的是,您可以使用 as 运算符将对象转换为接口。

有关详细信息,请参阅本文: http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx

还有一块拼图。接口不是从object 派生的: http://blogs.msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx

【讨论】:

m_Clientobj 几乎可以肯定是同一个对象(除非定义了转换)。我不认为这很重要......【参考方案2】:

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

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

【讨论】:

这也是我的第一个想法。 绝对是一种可能性。参考错误。但是这样的事情通常在调试时起作用,而在部署时不起作用(部署时的不同程序集)。每当这发生在我身上,因为 Activator.CreateInstance 不会主动加载与其实例化的类型关联的所有程序集。 在我的例子中,同一个程序集部署在 2 个不同的目录中。该类型在一个地方动态加载,并从另一个程序集转换为接口。【参考方案3】:

如果类 FPG.H60​​.AFF.TabControlH60 确实实现了 IFrameworkClient,那么应该没有理由会失败。我能想到的唯一导致此异常的情况是,如果包含 IFrameworkClient 的程序集是强命名的,并且选项卡控件对象碰巧引用了包含程序集的不同版本,或者您正在使用名称为 IFrameworkClient 的不同接口。

【讨论】:

【参考方案4】:

有些东西告诉我你的示例代码遗漏了一些东西......

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);

【讨论】:

【参考方案5】:

在独立项目(类库)的独立命名空间(必须有命名空间)中定义IFrameworkClient接口。然后将类库的引用添加到Control项目和主项目中

【讨论】:

【参考方案6】:

我的库提供“插件”功能时遇到同样的问题......我终于让它工作了......

这是我的问题:我有一个使用插件的主程序集,一个使用插件 (Plugin.dll) 的程序集和(重要的)另一个提供插件功能的程序集 (Library.dll)。

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

主程序集也引用了插件函数。为了使用“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”。

线索是:确保不要在不同的上下文中访问两个程序集!

【讨论】:

您,先生,刚刚给我带来了困扰我 4 个小时的问题,请走开。非常感谢! 非常有帮助的答案,在遇到类似问题时为我节省了很多时间。谢谢!【参考方案7】:

Interface 在不同的程序集中并且我在run-time 在不同的程序集中动态获得我的课程时,interface casting 将像您的一样失败示例(C# 知道我们的接口是一种不同于类从该接口继承的类型)。

这是我在这种情况下简单而有用的技巧:

当我确定我的Class 继承自提到的Interface(eq.IFrameworkClient)时,我会像这样编写一段神奇的代码

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

通过这种技术,您可以:

design timedesign time 基于Interface members 信息和vs 编辑器智能系统的这行代码之后编写您的代码。 防止run-time 出现任何接口转换错误

注意事项:

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

【讨论】:

【参考方案8】:

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

在这种情况下我使用构建事件(而不是添加 DLL 作为引用)的原因是架构使得主应用程序应该只引用接口类型,而其他所有内容都应该动态加载。

TLDR; 在从另一个 DLL 动态加载类型的情况下,请确保使用构建事件将该 DLL 的最新版本复制到 bin 目录,否则当它看起来应该进行时,转换可能无法工作。

【讨论】:

【参考方案9】:

我遇到了同样的问题,我只是添加了以下代码

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

虽然在生产中它永远不会成为问题,但在单元测试中它是但现在我不需要再次加载它并创建“不同类型”

【讨论】:

以上是关于.NET:无法将对象转换为它实现的接口的主要内容,如果未能解决你的问题,请参考以下文章

无法将类型为“Microsoft.Office.Interop.Word.ApplicationClass”的 COM 对象强制转换为接口类型

C#无法将类型为"System.__ComObject"的 COM 对象强制转换为接口类

当两个类型参数在C#中实现公共接口时,如何将泛型强制转换为它实现的接口

无法将类型“System.String”的对象转换为类型“System.Byte []”错误 MYSQL NET CORE 3.1

System.InvalidCastException: 无法将类型为“LabelManager2.ApplicationClass”的 COM对象强制转换为

无法将“X”类型的对象转换为“X”类型 - ASP.NET