程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#插件開發簡單模型

C#插件開發簡單模型

編輯:關於C#

一、前言

插件模型指應用程序由一些動態的獨立模塊構成,每個模塊均具有一個或多個服務,並滿足一定的插件協議,能夠借助主程序實現主程序-插件,插件-插件之間的通訊。它定義了一套公共的接口,通過接口與插件進行通信,主要是通過反射來獲取相關的屬性和方法,然後再執行指定的操作。其實,它也可以理解為定義一套通用的解決方案,通過反射來獲取相應的程序集的相關類型,然後執行這些指定類型的相關操作。它是一種即插即用的方案,更新及維護簡便。

本文僅僅是描述插件開發的大體模型,設計比較簡單,主要的步驟如下:

(1)、定義公共的接口以及抽象類。

(2)、定義和實現相關組件。

(3)、實現通用程序集反射操作類。

其中,公共的接口和抽象類定義在組件Jasen.Framework.Core中,該組件中提供通用程序集反射操作類AssemblyUtility;具體實現的相關組件為Jasen.Framework.Oracle、Jasen.Framework.Access和Jasen.Framework.SqlServer,它們都實現了Jasen.Framework.Core中的公共接口。客戶端可以根據實際情況來進行相應的操作。相關組件圖如下:

二、公共接口和抽象類的定義以及相關組件的定義和實現

首先,定義公共的接口以及抽象類,如下類圖所示,定義一個公共的接口IDataTable,定義一個抽象類DataTable,這些公共的類型放置在最頂端的程序集中。而其他組件將分別重新創建,實現相對應的功能,如SqlServerDataTable、OracleDataTable和AccessDataTable實現各自的功能。注意:Assembly.LoadFile(file)動態加載程序集時,該程序集在當前的運行環境中必須不存在的,否則可能會出現意想不到的數據異常,因此相關組件的實現必須是獨立的(僅僅是實現公共的接口)。

三、通用程序集反射操作類的實現

下面的AssemblyUtility主要是對程序集操作的通用類,可以根據指定目錄以及文件列表動態獲取相應的程序集。同時,也可以通過目錄,文件以及程序集獲取相關的類型集合和對象集合。其中需要注意的是,實現的子類必須提供默認構造函數。客戶端可以通過該類獲取相應的類型和對象集合,然後再執行相應的操作。這些操作都是通過動態加載程序集來實現的,代碼如下所示:

public static class AssemblyUtility
    {
        public static IEnumerable<Type> GetImplementdTypesByDirectory<T>(string baseDirectory)
        {
           IList<Assembly> assemblies= GetAssemblies(baseDirectory);
           List<Type> types = new List<Type>();
           foreach (Assembly assembly in assemblies)
           {
               types.AddRange(GetImplementdTypes<T>(assembly));
           }
    
           return types;
        }
    
        public static IEnumerable<Type> GetImplementdTypes<T>(string assemblyFile)
        {
            if (!File.Exists(assemblyFile))
            {
                return null;
            }
            try
            {
                return GetImplementdTypes<T>(Assembly.LoadFile(assemblyFile));
            }
            catch (Exception ex)
            {
                return null;
            }
        }
    
        public static IEnumerable<Type> GetImplementdTypes<T>(Assembly assembly)
        {
            if (assembly == null)
            {
                return null;
            }
    
            return assembly.GetExportedTypes().Where(p =>
               p.IsSubclassOf(typeof(T)) && (!p.IsAbstract) && (!p.IsInterface));
        }
    
        public static IList<T> GetImplementedObjectsByDirectory<T>(string baseDirectory)
        {
            IList<Assembly> assemblies = GetAssemblies(baseDirectory);
            List<T> entities = new List<T>();
            foreach (Assembly assembly in assemblies)
            {
                entities.AddRange(GetImplementedObjects<T>(assembly));
            }
    
            return entities;
        }
    
        public static IList<T> GetImplementedObjects<T>(string assemblyFile)
        {
            if (!File.Exists(assemblyFile))
            {
                return null;             
            }
            try
            {
                return GetImplementedObjects<T>(Assembly.LoadFile(assemblyFile));
            }
            catch (Exception ex)
            {
                return null;
            }
        }
    
        public static IList<T> GetImplementedObjects<T>(Assembly assembly)
        {
            if (assembly == null)
            {
                return null;
            }
    
            IEnumerable<Type> types = GetImplementdTypes<T>(assembly);
            var result = new List<T>();
    
            foreach (Type type in types)
            {
                ConstructorInfo constructor = type.GetConstructor(new Type[0]);
                if (constructor == null)
                {
                    continue;
                }
    
                object instance = Activator.CreateInstance(type);
                if (instance is T)
                {
                    result.Add((T)instance);
                }
            }
    
            return result;
        }
    
        public static IList<Assembly> GetAssemblies(string baseDirectory)
        {
            if (!Directory.Exists(baseDirectory))
            {
                return new List<Assembly>();
            }
    
            string[] files = Directory.GetFiles(baseDirectory, "*.dll");
    
            return GetAssemblies(files);
        }
    
        public static IList<Assembly> GetAssemblies(string[] assemblyFiles)
        {
            IList<Assembly> assemblies = new List<Assembly>();
            try
            {
                foreach (string file in assemblyFiles)
                {
                    if (!File.Exists(file)||(!file.EndsWith(".dll",StringComparison.InvariantCultureIgnoreCase)))
                    {
                        continue;
                    }
                    assemblies.Add(Assembly.LoadFile(file));
                }
            }
            catch (Exception ex)
            {
                return new List<Assembly>();
            }
    
            return assemblies;
        }
    }

public static IEnumerable<Type> GetImplementdTypesByDirectory<T>(string baseDirectory)

public static IEnumerable<Type> GetImplementdTypes<T>(string assemblyFile)

public static IList<T> GetImplementedObjects<T>(Assembly assembly)

以上3個方法根據不同的參數(目錄、地址、程序集)來動態獲取程序集中的特定類型集合,這些類型為類型T的類或者子類(非抽象類和接口)。

public static IList<T> GetImplementedObjectsByDirectory<T>(string baseDirectory)

public static IList<T> GetImplementedObjects<T>(string assemblyFile)

public static IList<T> GetImplementedObjects<T>(Assembly assembly)

而以上3個方法根據不同的參數(目錄、地址、程序集)來動態獲取程序集中的特定對象集合,這些對象為類型T的類或者子類(非抽象類和接口)的實例。當組件中子類存在有參構造函數時,必須實現默認構造函數。從如下代碼可以看出:如果默認構造函數不存在,將不會添加該對象實例。

ConstructorInfo constructor = type.GetConstructor(new Type[0]);

if (constructor == null)

{

   continue;

}

object instance = Activator.CreateInstance(type);

if (instance is T)

{

   result.Add((T)instance);

}

四、通用程序集反射操作類的單元測試

AssemblyUtility類主要的單元測試如下,僅驗證了正確的情況,代碼如下:

 public class AssemblyUtilityTest
{
[TestMethod()]
public void GetAssembliesTest()
{
string assemblyPath = AppDomain.CurrentDomain.BaseDirectory+"\\Files\\";
IList<Assembly> result = AssemblyUtility.GetAssemblies(assemblyPath);
Assert.IsNotNull(result);
Assert.AreEqual(3, result.Count);
}
[TestMethod()]
public void GetAssembliesByFilesTest()
{
string[] assemblyFiles = new string[] { AppDomain.CurrentDomain.BaseDirectory + "\\Jasen.Framework.Core.dll",
AppDomain.CurrentDomain.BaseDirectory + "\\Jasen.Framework.Core.Test.dll",
"www",
"ww.dll"};
IList<Assembly> result = AssemblyUtility.GetAssemblies(assemblyFiles);
Assert.IsNotNull(result);
Assert.AreEqual(2, result.Count);
}
[TestMethod()]
public void GetImplementedObjectsByDirectoryTest()
{
string assemblyDir = AppDomain.CurrentDomain.BaseDirectory + "\\Files\\";
IList<DataTable> result = AssemblyUtility.GetImplementedObjectsByDirectory<DataTable>(assemblyDir);
Assert.IsNotNull(result);
Assert.AreEqual(3, result.Count);
}
[TestMethod()]
public void GetImplementedObjectsTest()
{
string assemblyFile =AppDomain.CurrentDomain.BaseDirectory + "\\Files\\Jasen.Framework.Oracle.dll";
IList<DataTable> result = AssemblyUtility.GetImplementedObjects<DataTable>(assemblyFile);
Assert.IsNotNull(result);
Assert.AreEqual(1, result.Count);
}
[TestMethod()]
public void GetImplementedTypesTest()
{
string assemblyFile = AppDomain.CurrentDomain.BaseDirectory + "\\Files\\Jasen.Framework.Oracle.dll";
IEnumerable<Type> types = AssemblyUtility.GetImplementdTypes<DataTable>(assemblyFile);
Assert.IsNotNull(types);
int count = 0;
foreach (var type in types)
{
Assert.IsTrue(type.IsSubclassOf(typeof(DataTable)));
Assert.IsFalse(type.IsAbstract);
Assert.IsFalse(type.IsInterface);
count++;
}
Assert.AreEqual(1, count);
}
[TestMethod()]
public void GetImplementdTypesByDirectoryTest()
{
string assemblyDir = AppDomain.CurrentDomain.BaseDirectory + "\\Files\\";
IEnumerable<Type> types = AssemblyUtility.GetImplementdTypesByDirectory<DataTable>(assemblyDir);
Assert.IsNotNull(types);
int count = 0;
foreach (var type in types)
{
Assert.IsTrue(type.IsSubclassOf(typeof(DataTable)));
Assert.IsFalse(type.IsAbstract);
Assert.IsFalse(type.IsInterface);
count++;
}
Assert.AreEqual(3, count);
}
}

五、總結

全文中主要圍繞AssemblyUtility通用類來進行講解的,僅僅是插件開發的一個思路。具體應用的話,應該相對來說比較直接,在客戶端獲取相應的類型集合以及對象集合,然後再執行這些集合的具體操作即可。其中,實現的組件(插件)放置在指定的目錄下,通過AssemblyUtility類即可動態加載目錄下的程序集,從而獲取到指定類型的數據。具體執行什麼操作,實現什麼功能,這些都是在組件(插件)中實現即可。

源代碼下載:C#插件開發模型源代碼

http://files.cnblogs.com/jasenkin/Jasen.Framework.AssemblySample.rar

作者:JasenKin

出處:http://www.cnblogs.com/jasenkin/

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved