กลไกการสะท้อนที่จัดทำโดย .NET สามารถโหลดปลั๊กอินได้อย่างง่ายดาย บทความนี้แสดงวิธีการที่สามารถโหลดปลั๊กอินที่จำเป็นได้อย่างยืดหยุ่นและถูกต้อง
ใน .NET ชื่อประเภทที่สมบูรณ์จะมีรูปแบบ "ชื่อประเภท ชื่อแอสเซมบลี"
ตัวอย่างเช่น: "System.Configuration.NameValueSectionHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
ชื่อประเภทคือ: System.Configuration.NameValueSectionHandler ซึ่งเป็นชื่อประเภทที่สมบูรณ์พร้อมเนมสเปซ
คุณยังสามารถรับ FullName ได้โดยใช้ประเภท
ตัวอย่างเช่น: สตริง typeName = typeof(NameValueSectionHandler).FullName;
ชื่อแอสเซมบลีคือ: "System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
แอสเซมบลีมีชื่อว่า System และระบบจะปรับส่วนขยายโดยอัตโนมัติ (เช่น System.dll หรือ System.exe)
เวอร์ชัน วัฒนธรรม และ PublicKeyToken เป็นเวอร์ชันเฉพาะ พื้นหลังทางวัฒนธรรม และลายเซ็นต์ของแอสเซมบลี ไม่มีข้อกำหนดเฉพาะ และสามารถละเว้นได้
เราสามารถโหลดประเภทที่ต้องการแบบไดนามิกตามชื่อของประเภท ชอบ:
string typeName = "System.Configuration.NameValueSectionHandler, ระบบ";
พิมพ์ t = Type.GetType(typeName);
วัตถุ obj = Activator.CreateInstance(t);
//หรือ
System.Configuration.NameValueSectionHandler obj = (System.Configuration.NameValueSectionHandler) Activator.CreateInstance(t);
ณ จุดนี้ obj คืออินสแตนซ์ประเภทที่ต้องการ
โดยปกติแล้วปลั๊กอินคือคลาสที่จำเป็นต้องใช้อินเทอร์เฟซบางอย่าง ดังนั้น ก่อนที่จะโหลดปลั๊กอิน คุณต้องพิจารณาว่าประเภทปลั๊กอินนั้นเหมาะสมหรือไม่
ตัวอย่างเช่น หากอินเทอร์เฟซของปลั๊กอินคือ IPlugin เราสามารถระบุได้ด้วยวิธีต่อไปนี้:
สตริง interfaceName = typeof (IPlugin) ชื่อเต็ม;
string typeName = "Muf.MyPlugin, MyPlugin";
พิมพ์ t = Type.GetType(typeName);
ถ้า ( เสื้อ == โมฆะ
||. !t.IsClass
||. !t.เป็นสาธารณะ
||. t.GetInterface(ชื่ออินเตอร์เฟส) == null)
-
return null; // ไม่ใช่ปลั๊กอินที่จำเป็น
-
เมื่อสรุปโค้ดข้างต้นแล้ว เราสามารถสร้างโค้ดทั่วไปสำหรับการโหลดปลั๊กอินได้:
/***////// <สรุป>
/// โหลดและสร้างประเภทแบบไดนามิกที่มีอินเทอร์เฟซที่ระบุ
/// </สรุป>
/// <param name="className">พิมพ์ชื่อ</param>
/// <param name="interfaceName">ชื่ออินเตอร์เฟสที่ระบุ</param>
/// <param name="param">ระบุพารามิเตอร์ของตัวสร้าง (อาร์เรย์ว่างหรือว่างหมายถึงการเรียกตัวสร้างเริ่มต้น)</param>
/// <returns>ส่งคืนประเภทที่สร้างขึ้น (null หมายความว่าไม่สามารถสร้างหรือไม่พบประเภท)</returns>
LoadObject วัตถุคงที่สาธารณะ (ชื่อคลาสสตริง, ชื่ออินเตอร์เฟสสตริง, พารามิเตอร์วัตถุ [])
-
พยายาม
-
พิมพ์ t = Type.GetType(ชื่อคลาส);
ถ้า ( เสื้อ == โมฆะ
||. !t.IsClass
||. !t.เป็นสาธารณะ
||.t.เป็นนามธรรม
||. t.GetInterface(ชื่ออินเตอร์เฟส) == null)
-
กลับเป็นโมฆะ;
}
วัตถุ o = Activator.CreateInstance (t, พารามิเตอร์);
ถ้า (o == โมฆะ)
-
กลับเป็นโมฆะ;
-
กลับหรือ;
-
จับ (ข้อยกเว้นเช่น)
-
กลับเป็นโมฆะ;
-
-
หลังจากนั้น เราสามารถใช้ LoadObject เพื่อโหลดปลั๊กอินที่จำเป็นได้
โดยทั่วไปปลั๊กอินจะอยู่ในไฟล์การกำหนดค่าและอ่านโดยโปรแกรม:
ตัวอย่างไฟล์การกำหนดค่า (ดูบทความที่เกี่ยวข้องของฉันสำหรับการใช้ไฟล์การกำหนดค่า):
<?xml version="1.0" encoding="utf-8" ?>
<การกำหนดค่า>
<configSections>
<ชื่อส่วน = "Channels" type = "Vmp.Configuration.ChannelsSectionHandler, การสื่อสาร" />
</configSections>
<ช่อง>
<ช่อง
ChannelType = "Vmp.Communication.TcpChannel, การสื่อสาร"
TraceFile = "d:logchannel1.log"
พอร์ต = "2020" MaxConnections = "300" BufferSize = "2048"
-
</ช่อง>
</การกำหนดค่า>
ตัวอย่างโค้ด:
ArrayList channelList ส่วนตัว = new ArrayList();
LoadChannels ส่วนตัว ()
-
ArrayList channelConfig = (ArrayList)ConfigurationSettings.GetConfig( "ช่อง" );
foreach (การกำหนดค่า Hashtable ใน channelConfig)
-
string channelType = (string) config["ChannelType"];
IChannel channel = (IChannel) CommonUtils.LoadObject(channelType, typeof(IChannel).FullName, วัตถุใหม่[]{config});
ถ้า (ช่อง == โมฆะ)
ดำเนินการต่อ;
channelList.Add (ช่อง);
}
คุณยังสามารถสำรวจไดเร็กทอรีปลั๊กอินที่ระบุและโหลดปลั๊กอินทั้งหมดที่ตรงตามข้อกำหนด เช่น:
IPlugin สาธารณะ[] LoadAllPlugIn(string PluginDir)
-
//ตั้งค่าไดเร็กทอรีปลั๊กอินเริ่มต้น
ถ้า (pluginDir == null || PluginDir == "")
PluginDir = "./PlugIns";
// รับชื่ออินเทอร์เฟซปลั๊กอิน
string interfaceName = typeof(IPlugin).FullName;
// อาร์เรย์ที่ใช้ในการจัดเก็บปลั๊กอิน
ArrayList arr = new ArrayList();
// สำรวจไดเร็กทอรีปลั๊กอิน (สมมติว่าปลั๊กอินเป็นไฟล์ dll)
foreach (ไฟล์สตริงใน Directory.GetFiles (pluginDir, "*.dll"))
-
//โหลดไฟล์ปลั๊กอิน
แอสเซมบลี asm = Assembly.LoadFile (ไฟล์);
// สำรวจคลาสปลั๊กอินที่ส่งออก
foreach(พิมพ์ t ใน asm.GetExportedTypes())
-
//โหลดปลั๊กอิน หากปลั๊กอินไม่สอดคล้องกับอินเทอร์เฟซที่ระบุ ให้คืนค่า null
ปลั๊กอิน IPlugin = LoadObject(t.FullName, interfaceName, null) เป็น IPlugin;
if(plugin != null)
arr.Add(ปลั๊กอิน);
-
}
// กลับสู่ปลั๊กอิน
กลับ (IPlugin[])arr.ToArray(typeof(IPlugin));
-