从动态加载程序集创建对象并将其转换为接口(.NET 2.0) [英] Create object from dynamically load assembly and cast it to interface (.NET 2.0)
问题描述
主应用程序(加载插件):
命名空间Console_IFce_Test
{
class Program
{
static void Main(string [] args)
{
Console.WriteLine(按任意键找到IPlugin库.. 。);
Console.ReadKey();
string [] files = Directory.GetFiles(Directory.GetCurrentDirectory(),* .dll);
Console.WriteLine(加载程序集:{0},Path.GetFileName(files [0]));
Assembly asm = Assembly.LoadFrom(files [0]);
//尝试这个,但仍然有问题
//装配asm = Assembly.Load(File.ReadAllBytes(files [0]));
foreach(在asm.GetTypes()中键入t)
{
Console.WriteLine(搜索类型{0} ...,t.FullName);
foreach(在t.GetInterfaces()中输入iface)
{
Console.WriteLine(interface found:{0},iface.FullName);
}
if(t is IPlugin)
{
Console.WriteLine(1 - IPlugin found!);
IPlugin plugin =(IPlugin)Activator.CreateInstance(t);
return;
}
if(typeof(IPlugin).IsAssignableFrom(t))
{
Console.WriteLine(2 - IPlugin found!);
IPlugin plugin =(IPlugin)Activator.CreateInstance(t);
return;
}
}
Console.WriteLine(所有操作完成!按任意键退出...);
Console.ReadKey();
}
}
}
界面:
命名空间Console_IFce_Test
{
接口IPlugin
{
int GetZero();
}
}
插件:
命名空间库
{
public class Plugin:Console_IFce_Test.IPlugin
{
public int GetZero()
{
return 0;
}
}
}
在带有.exe的目录中 - 只有1 .dll(插件)。所以,它的输出:
按任意键找到IPlugin库...
加载程序集:Library.dll
搜索类型Console_IFce_Test.IPlugin ...
搜索类型Library.Plugin ...
找到的接口:Console_IFce_Test.IPlugin
所有操作完成!按任意键退出...
你看,该程序在程序集中找到了IPlugin界面,但是当我试图与接口(两个条件语句)进行比较 - 它们返回false。如果我尝试手动转换它,它会返回异常Can not cast。
我发现类似的问题:两种类型不等于应该是,作者的答案写道:
不同应用程序域[.NET]或类
加载程序[Java]加载的相同类/类型将不会比较相等,不能分配给/从
对方直接。
但我不明白我该怎么办?而且如何?
您需要以某种方式使.NET将程序集加载到同一上下文以便能够执行在这些程序集中的类型之间。
1-将程序集放在应用程序路径或GAC中,以便Load(而不是LoadFrom)功能可以找到它。
2-创建一个应用程序域,并进行所有的工作。您可以完全控制程序集在哪里搜索应用程序域。
3-使用加载项模型。
阅读本文以了解有关您的选项的更多信息:装配加载的最佳做法
I have a problem with dynamically loaded assemblys and casting it to interface. Where is my mistake?
Main app (load plugins):
namespace Console_IFce_Test
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press any key to find IPlugin library...");
Console.ReadKey();
string[] files = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.dll");
Console.WriteLine("Loading assembly: {0}", Path.GetFileName(files[0]));
Assembly asm = Assembly.LoadFrom(files[0]);
//Trying this, but still have problems
//Assembly asm = Assembly.Load(File.ReadAllBytes(files[0]));
foreach (Type t in asm.GetTypes())
{
Console.WriteLine("Searching in type {0}... ", t.FullName);
foreach (Type iface in t.GetInterfaces())
{
Console.WriteLine("Interface found: {0}", iface.FullName);
}
if (t is IPlugin)
{
Console.WriteLine("1 - IPlugin found!");
IPlugin plugin = (IPlugin)Activator.CreateInstance(t);
return;
}
if (typeof(IPlugin).IsAssignableFrom(t))
{
Console.WriteLine("2 - IPlugin found!");
IPlugin plugin = (IPlugin)Activator.CreateInstance(t);
return;
}
}
Console.WriteLine("All operations done! Press any key to exit...");
Console.ReadKey();
}
}
}
Interface:
namespace Console_IFce_Test
{
interface IPlugin
{
int GetZero();
}
}
And plugin:
namespace Library
{
public class Plugin : Console_IFce_Test.IPlugin
{
public int GetZero()
{
return 0;
}
}
}
In directory with .exe - only 1 .dll (plugin). So, it's output:
Press any key to find IPlugin library...
Loading assembly: Library.dll
Searching in type Console_IFce_Test.IPlugin...
Searching in type Library.Plugin...
Interface found: Console_IFce_Test.IPlugin
All operations done! Press any key to exit...
You see, that program found IPlugin interface in assembly, but when i trying to compare it with interface (two conditional statements) - they return false. And if i trying to manually cast it - it returns exception "Can't cast".
I found similar problem: Two Types not equal that should be , and author of answer write:
The same class / type loaded by different app domains [.NET] or class loaders [Java] will not compare equal and are not assignable to/from each other directly.
But i can't understand what should i do? And how?
You need to somehow make .NET to load the assemblies to the same context to be able to do a cast between the types in those assemblies.
1- Put the assembly in the application path or GAC so that the Load (not the LoadFrom) function will find it.
2- Create an app domain and do all of the work there. You can fully control where the assemblies are being searched for an app domain.
3- Use the add-in model.
Read this article to learn more about your options: Best Practices for Assembly Loading
这篇关于从动态加载程序集创建对象并将其转换为接口(.NET 2.0)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!