.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_Client
和 obj
几乎可以肯定是同一个对象(除非定义了转换)。我不认为这很重要......【参考方案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 time
design 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对象强制转换为