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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1596796/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 19:11:36  来源:igfitidea点击:

.NET: Unable to cast object to interface it implements

c#interfacecastingbase-classactivator

提问by user193327

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?

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

回答by Kennet Belenky

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

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

IFrameworkClient fc = (IFrameworkClient)m_Client;

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 asoperator.

或者,我有点确定您可以从对象到as操作员的界面进行转换。

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

有关更多信息,请参阅本文: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

又是一块拼图。接口并非源自objecthttp: //blogs.msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx

回答by Marc Gravell

The most likely cause here is that IFrameworkClientis 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.

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

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.

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

回答by Szymon Rozga

If the class FPG.H60.AFF.TabControlH60actually 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.

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

回答by Szymon Rozga

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.

我敢打赌,在您尝试转换之前,尚未加载包含 IFrameworkClient 定义的 DLL。当您使用 Activator.CreateInstance 时可能会发生这种情况。

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

尝试var forceLoad = typeof(IFrameworkClient);在演员之前插入。

回答by SMAH1

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

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

回答by Andi

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

这是我的问题:我有一个使用插件的主程序集,一个带有插件的程序集(Plugin.dll)和(重要的)另一个提供插件功能的程序集(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.

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

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

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

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

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

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!

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

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.

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

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

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

回答by RAM

When the Interfaceis in a different assemblyand i get my class dynamicallyat run-timein a different assembly, interface castingwill be failed like your sample (C# knows our interface as a different type than which one the class inherited from that).

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

This is my simple and useful technique in this cases:

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

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

当我确定我Class已经从提到的Interface(eq. IFrameworkClient)继承了,所以我写了这样一行神奇的代码

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

By this technique you can:

通过这种技术,您可以:

  • Write your codes after this line of code for fcat design timebase on Interface membersinfo and vs editor intelligences system.
  • Prevent any interface casting error at run-time
  • fcdesign time基于Interface members信息和 vs 编辑器智能系统的这行代码之后编写您的代码。
  • 防止任何接口转换错误 run-time

Notes:

笔记:

  • You need C# v4to use dynamictype
  • Usually i don't like to use dynamictypes in my codes but it can help us in some cases like this
  • 您需要C# v4使用dynamic类型
  • 通常我不喜欢dynamic在我的代码中使用类型,但它可以在某些情况下帮助我们

回答by KthProg

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.

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

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.

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

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.

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

回答by T.S.

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"

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