[英]Loading DLLs at runtime in C#
我想弄清楚如何在 C# 應用程序中在運行時導入和使用 .dll。 使用 Assembly.LoadFile() 我已經設法讓我的程序加載 dll(這部分肯定有效,因為我能夠使用 ToString() 獲取類的名稱),但是我無法使用“輸出”我的控制台應用程序中的方法。 我正在編譯 .dll,然后將其移動到我的控制台項目中。 在 CreateInstance 和能夠使用這些方法之間是否有額外的步驟?
這是我的 DLL 中的類:
namespace DLL
{
using System;
public class Class1
{
public void Output(string s)
{
Console.WriteLine(s);
}
}
}
這是我要加載 DLL 的應用程序
namespace ConsoleApplication1
{
using System;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
foreach(Type type in DLL.GetExportedTypes())
{
var c = Activator.CreateInstance(type);
c.Output(@"Hello");
}
Console.ReadLine();
}
}
}
成員必須在編譯時可解析才能直接從 C# 調用。 否則,您必須使用反射或動態對象。
反射
namespace ConsoleApplication1
{
using System;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
foreach(Type type in DLL.GetExportedTypes())
{
var c = Activator.CreateInstance(type);
type.InvokeMember("Output", BindingFlags.InvokeMethod, null, c, new object[] {@"Hello"});
}
Console.ReadLine();
}
}
}
動態 (.NET 4.0)
namespace ConsoleApplication1
{
using System;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
foreach(Type type in DLL.GetExportedTypes())
{
dynamic c = Activator.CreateInstance(type);
c.Output(@"Hello");
}
Console.ReadLine();
}
}
}
現在,您正在為程序集中定義的每個類型創建一個實例。 您只需要創建Class1
的單個實例即可調用該方法:
class Program
{
static void Main(string[] args)
{
var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
var theType = DLL.GetType("DLL.Class1");
var c = Activator.CreateInstance(theType);
var method = theType.GetMethod("Output");
method.Invoke(c, new object[]{@"Hello"});
Console.ReadLine();
}
}
您需要創建一個公開Output
方法的類型的實例:
static void Main(string[] args)
{
var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
var class1Type = DLL.GetType("DLL.Class1");
//Now you can use reflection or dynamic to call the method. I will show you the dynamic way
dynamic c = Activator.CreateInstance(class1Type);
c.Output(@"Hello");
Console.ReadLine();
}
Activator.CreateInstance()
返回一個對象,該對象沒有 Output 方法。
看起來你來自動態編程語言? C# 絕對不是那樣,你想要做的事情會很困難。
由於您是從特定位置加載特定 dll,也許您只想將其添加為對您的控制台應用程序的引用?
如果您絕對想通過Assembly.Load
加載程序Assembly.Load
,則必須通過反射調用c
任何成員
類似於type.GetMethod("Output").Invoke(c, null);
應該這樣做。
foreach (var f in Directory.GetFiles(".", "*.dll"))
Assembly.LoadFrom(f);
這會加載可執行文件文件夾中的所有 DLL。
就我而言,我試圖使用Reflection
來查找一個類的所有子類,即使在其他 DLL 中也是如此。 這有效,但我不確定這是否是最好的方法。
編輯:我計時,它似乎只在第一次加載它們。
Stopwatch stopwatch = new Stopwatch();
for (int i = 0; i < 4; i++)
{
stopwatch.Restart();
foreach (var f in Directory.GetFiles(".", "*.dll"))
Assembly.LoadFrom(f);
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
}
輸出:34 0 0 0
因此,為了以防萬一,可以在任何反射搜索之前運行該代碼。
這不是那么困難。
您可以檢查已加載對象的可用功能,如果您按名稱找到了您要查找的功能,則窺探其預期參數(如果有)。 如果是您要查找的調用,則使用 MethodInfo 對象的 Invoke 方法調用它。
另一種選擇是簡單地將外部對象構建到接口,並將加載的對象轉換為該接口。 如果成功,則本地調用該函數。
這是很簡單的事情。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.