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

9 回答 9

45

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

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

Plugin.dll 引用了主程序集(以便能够扩展它)和带有插件函数的 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”。

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

于 2011-06-30T08:29:29.727 回答
13

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

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

于 2009-10-20T19:34:50.977 回答
5

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

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

当我确定我Class的继承自上述Interface(eq. IFrameworkClient) 时,我编写了这样一段神奇的代码

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

通过这种技术,您可以:

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

笔记:

  • 你需要C# v4使用dynamic类型
  • 通常我不喜欢dynamic在我的代码中使用类型,但在某些情况下它可以帮助我们
于 2015-06-30T19:01:01.677 回答
4

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

于 2011-01-27T10:29:14.100 回答
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);在演员表之前插入。

于 2009-10-20T19:36:46.470 回答
0

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

于 2009-10-20T19:36:42.633 回答
0

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

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

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

于 2017-03-27T16:18:58.337 回答
0

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

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

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

于 2019-09-19T06:37:46.360 回答
-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

于 2009-10-20T19:34:01.297 回答