C# .NET:无法将对象强制转换为其实现的接口
我有一个类(TabControlH60),它既继承了基类(UserControl),又实现了接口(IFrameworkClient)。我使用.NET Activator类实例化该对象。对于返回的实例,我可以强制转换到UserControl基类,但不能转换到接口。我得到的例外情况是代码snipet以下。如何向界面强制转换C# .NET:无法将对象强制转换为其实现的接口,c#,interface,casting,base-class,activator,C#,Interface,Casting,Base Class,Activator,我有一个类(TabControlH60),它既继承了基类(UserControl),又实现了接口(IFrameworkClient)。我使用.NET Activator类实例化该对象。对于返回的实例,我可以强制转换到UserControl基类,但不能转换到接口。我得到的例外情况是代码snipet以下。如何向界面强制转换 object obj = Activator.CreateInstance(objType); Type[] interfaces = obj.GetType().GetInte
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'."}
强制转换不起作用,因为您正在尝试从类型
对象
强制转换到接口。如果将接口转换线替换为:
IFrameworkClient fc=(IFrameworkClient)m_客户端代码>
它会起作用的
或者,我可以稍微确定您可以使用as
操作符从对象到接口进行转换
有关更多信息,请参阅本文:
还有一块拼图。接口不是从对象派生的:
这里最可能的原因是IFrameworkClient
在这两种情况下来自不同的程序集,因此是不同的.NET类型。即使是相同的代码,也可以是不同的类型
检查AssemblyQualifiedName
。另外请注意,如果您使用反射加载此程序集,则即使使用相同的AssemblyQualifiedName,也可以获得不同的类型,这要归功于加载上下文。如果类FPG.H60.AFF.TabControlH60确实实现了IFrameworkClient,则没有任何失败的原因。我能想到的唯一一件导致此异常的事情是,如果包含IFrameworkClient的程序集具有强名称,并且Tab控件对象恰好引用了包含该程序集的不同版本,或者您使用的是名为IFrameworkClient的不同接口。某种情况告诉我您的示例代码留下了一些错误塞满
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)代码>在转换之前。在独立项目(类库)的独立名称空间(必须有名称空间)中定义IFrameworkClient接口。然后添加类库的引用以控制项目和主项目我认为我的库提供“插件”功能也存在同样的问题。。。我终于让它工作了
这就是我的问题:我有一个使用插件的主程序集,一个带有插件(plugin.dll)的程序集,以及(重要的)另一个提供插件功能的程序集(Library.dll)
Plugin.dll引用了主程序集(为了能够扩展它)和带有Plugin func的Library.dll。-它的二进制文件位于相对于主程序集的目录“/Plugins”中
主程序集还引用了插件func。为了使用“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”
提示是:请确保不要在不同的上下文中访问两个程序集 当接口
在另一个程序集中时,我在另一个程序集中的运行时动态地
获取我的类时,接口转换
将像您的示例一样失败(C#知道我们的接口是一种不同的类型,而不是类从中继承的类型)
这是我在这种情况下使用的简单实用的技巧:
当我确定我的类
继承了前面提到的接口
(eq.IFrameworkClient
)时,我就这样写了一行代码:
dynamic fc = obj as IFrameworkClient ?? (dynamic) obj;
通过此技术,您可以:
- 基于
接口成员信息和vs编辑器智能系统,在设计时为fc
的这行代码后编写代码
- 防止在运行时出现任何接口转换错误
注意事项:
- 您需要
C#v4
才能使用dynamic
类型
- 通常我不喜欢在代码中使用
动态
类型,但在某些情况下它可以帮助我们
在我的例子中,我必须添加一个构建事件来复制所需的DLL,因为我在运行时创建实例并分配给接口类型。否则,加载的DLL可能不是最新的DLL,因此可能不会强制转换到接口
我在本例中使用构建事件(而不是将DLL添加为引用)的原因是,该体系结构使得主应用程序只应引用接口类型,其他所有内容都应动态加载
TLDR;
如果从另一个DLL动态加载类型,请确保使用生成事件将该DLL的最新版本复制到bin目录,否则
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