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

发布于 2024-08-08 20:15:02 字数 654 浏览 12 评论 0原文

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

I have a class (TabControlH60) that both inherits from a base class (UserControl) and implements an interface (IFrameworkClient). I instantiate the object using the .NET Activator class. With the returned instance, I can cast to the UserControl base class, but not to the interface. The exception I get is below the code snipet. How do I cast to the interface?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

維他命╮ 2024-08-15 20:15:02

我的一个提供“插件”功能的库也有同样的问题...我终于让它工作了...

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

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

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

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

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

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

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

I hat the same problems with a library of mine providing "plugin"-functionality... I got it finally working...

Here was my problem: I had one main assembly using plugins, one assembly with the plugin (Plugin.dll) AND (important) another assembly providing the plugin-functionality (Library.dll).

The Plugin.dll referenced the main assembly (in order to be able to extend it) and the Library.dll with the plugin-func. - it's binaries got to a directory "./Plugins" relative to the main assembly.

The main assembly also referenced the plugin-func. assembly in order to use the "PluginManager" is wrote. This "PluginManager" gets a path and loads all *.dll files via reflection in order to analyze if there is a "IPlugin"-interface (which comes from Library.dll too).

Everytime I called the PluginManager to load the plugins it could not cast them to "IPlugin" although they implemented it.

I nearly got mad - but then I found out the whole problem. By compiling the plugin there was not only the "Plugin.dll" but the "Library.dll" written to the "./Plugins" directory. By accidentally loading the "Library.dll" every time with my PluginManager I now had two types of "IPlugin" - one in the actual "Library.dll" that is used from the main assembly and one that was loaded through my PluginManager - and those were incompatible!

Attention - if you just do not load "./Plugins/Library.dll" you nevertheless encounter the problem - because if you load "Plugin.dll" which references "Library.dll" then it just uses the one in the same directory... TILT...!! My PluginManager now just deletes "Library.dll" where it find it.

The clue is: Be sure that you do not access two assemblies in different contexts!

身边 2024-08-15 20:15:02

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

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

The most likely cause here is that IFrameworkClient is from a different assembly in the two cases, and is thus a different .NET type. Even if it is the same code, it can be a different type.

Check the AssemblyQualifiedName. Note also that if you are loading this assembly with reflection you can get a different type even with the same AssemblyQualifiedName, thanks to the load-context.

不甘平庸 2024-08-15 20:15:02

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

Define IFrameworkClient Interface in independent namespace (must be have namespace) of independent project (class library).Then add refrence of the class library to Control project and main project

格子衫的從容 2024-08-15 20:15:02

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

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

当我确定我的 Class 已从上述 Interface 继承时code> (eq. IFrameworkClient),所以我写了一行神奇的代码,如下所示:

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

通过这种技术,您可以:

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

注释:

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

When the Interface is in a different assembly and i get my class dynamically at run-time in a different assembly, interface casting will be failed like your sample (C# knows our interface as a different type than which one the class inherited from that).

This is my simple and useful technique in this cases:

When I'm sure my Class has inherited from the mentioned Interface (eq. IFrameworkClient), so i write one magic line of code like this:

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

By this technique you can:

  • Write your codes after this line of code for fc at design time base on Interface members info and vs editor intelligences system.
  • Prevent any interface casting error at run-time

Notes:

  • You need C# v4 to use dynamic type
  • Usually i don't like to use dynamic types in my codes but it can help us in some cases like this
千仐 2024-08-15 20:15:02

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

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

Something tells me your sample code is leaving some stuff out...

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 { }

This compiles and runs.

I'm betting that the DLL containing the definition of IFrameworkClient hasn't yet been loaded before you try to cast. This can happen when you're using Activator.CreateInstance.

Try inserting var forceLoad = typeof(IFrameworkClient); before the cast.

穿透光 2024-08-15 20:15:02

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

If the class FPG.H60.AFF.TabControlH60 actually does implement IFrameworkClient there should be no reason this would fail. The only thing I can think of that causes this exception is if the assembly that contains IFrameworkClient is strongly named and the Tab Control object happens to reference a different version of the containing assembly or your are using a different interface with the name IFrameworkClient.

阪姬 2024-08-15 20:15:02

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

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

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

In my case I had to add a build event to copy the needed DLL since I was creating instances and assigning to interface types at run time. Otherwise the DLL loaded might not be the most up-to-date DLL, and therefore may not cast to the interface.

The reason I used build events in this case (instead of adding the DLL as a reference) is that the architecture is such that the main application should only reference the interface types, and everything else should be loaded dynamically.

TLDR;
In the case of loading types dynamically from another DLL, make sure you copy the most recent version of that DLL to the bin directory using build events, otherwise casting may not work when it appears that it should.

红颜悴 2024-08-15 20:15:02

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

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

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

I ran into same issue and I just added the following code

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

Although, in production it will never be a problem, in unit test it was but now I don't need to load it again and create a "different type"

凝望流年 2024-08-15 20:15:02

转换不起作用,因为您正在尝试从类型 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

的另一部分谜。接口不是从对象派生的:
http://blogs. msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx

The cast isn't working because you're trying to cast from type object to the interface. If you replace the interface cast line with:

IFrameworkClient fc = (IFrameworkClient)m_Client;

It will work.

Alternately, I'm mildly certain that you could do the cast from the object to the interface with the as operator.

See this article for more information:
http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx

One more piece of the puzzle. Interfaces do not derive from object:
http://blogs.msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文