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

时间:2009-10-20 19:25:59

标签: c# interface casting base-class activator

我有一个类(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'."}

9 个答案:

答案 0 :(得分:37)

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

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

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

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

每当我调用PluginManager加载插件时,虽然他们实现了插件,但它无法将它们转换为“IPlugin”。

我差点生气 - 但后来我发现了整个问题。通过编译插件,不仅有“Plugin.dll”而且“Library.dll”写入“./Plugins”目录。每次使用我的PluginManager意外加载“Library.dll”时,我现在有两种类型的“IPlugin” - 一个在主程序集中使用的实际“Library.dll”中,另一个是通过我的PluginManager加载的 - 那些是不相容的!

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

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

答案 1 :(得分:11)

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

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

答案 2 :(得分:4)

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

答案 3 :(得分:3)

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

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

答案 4 :(得分:2)

如果Interface在另一个程序集中 ,并且我在run-time的另一个程序集中动态动态,{{1}将像你的样本一样失败(C#知道我们的接口与另一个类继承的类型不同)。

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

当我确定我的interface casting继承了上面提到的Class(例如Interface)时,我写了一行魔法代码这样:

IFrameworkClient

通过这种技术,你可以:

  • 根据dynamic fc = obj as IFrameworkClient ?? (dynamic) obj; 信息和编辑智能系统fc,在design time代码的这一行代码后面编写代码。
  • 防止Interface members
  • 处的任何界面投射错误

备注:

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

答案 5 :(得分:0)

如果类 FPG.H60​​.AFF.TabControlH60 实际上确实实现了IFrameworkClient,那么就没有理由这会失败。我唯一能想到的是导致此异常的原因是,包含IFrameworkClient的程序集是强命名的,并且Tab Control对象恰好引用了包含程序集的不同版本,或者您正在使用名为IFrameworkClient的其他接口。

答案 6 :(得分:0)

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

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

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

答案 7 :(得分:0)

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

library(dplyr)
df %>%
  group_by(ID) %>%
  mutate(count_n = dense_rank(Date))

#  ID    Date        need count_n
#  <fct> <date>     <dbl>   <int>
#1 x1    2006-08-23     1       1
#2 x1    2006-08-30     2       2
#3 x1    2006-08-30     2       2
#4 X2    2006-09-06     1       1
#5 X3    2006-09-13     1       1
#6 x1    2006-09-20     3       3

尽管在生产中这将永远不是问题,但在单元测试中却是,但是现在我不需要再次加载它并创建“不同类型”

答案 8 :(得分:-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