zoukankan      html  css  js  c++  java
  • C#插件开发简单模型

    一、前言

    插件模型指应用程序由一些动态的独立模块构成,每个模块均具有一个或多个服务,并满足一定的插件协议,能够借助主程序实现主程序-插件,插件-插件之间的 通讯。它定义了一套公共的接口,通过接口与插件进行通信,主要是通过反射来获取相关的属性和方法,然后再执行指定的操作。其实,它也可以理解为定义一套通 用的解决方案,通过反射来获取相应的程序集的相关类型,然后执行这些指定类型的相关操作。它是一种即插即用的方案,更新及维护简便。

    本文仅仅是描述插件开发的大体模型,设计比较简单,主要的步骤如下:

    (1)、定义公共的接口以及抽象类。

    (2)、定义和实现相关组件。

    (3)、实现通用程序集反射操作类。

     

    其中,公共的接口和抽象类定义在组件Jasen.Framework.Core中,该组件中提供通用程序集反射操作类AssemblyUtility;具体实现的相关组件为Jasen.Framework.Oracle、Jasen.Framework.Access和Jasen.Framework.SqlServer,它们都实现了Jasen.Framework.Core中的公共接口。客户端可以根据实际情况来进行相应的操作。相关组件图如下:

    \" longdesc=

     

     

    二、公共接口和抽象类的定义以及相关组件的定义和实现

    首 先,定义公共的接口以及抽象类,如下类图所示,定义一个公共的接口IDataTable,定义一个抽象类DataTable,这些公共的类型放置在最顶端 的程序集中。而其他组件将分别重新创建,实现相对应的功能,如SqlServerDataTable、OracleDataTable和 AccessDataTable实现各自的功能。注意:Assembly.LoadFile(file)动态加载程序集时,该程序集在当前的运行环境中必 须不存在的,否则可能会出现意想不到的数据异常,因此相关组件的实现必须是独立的(仅仅是实现公共的接口)。

    \" longdesc=

     

    三、通用程序集反射操作类的实现

    下 面的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类即可动态加 载目录下的程序集,从而获取到指定类型的数据。具体执行什么操作,实现什么功能,这些都是在组件(插件)中实现即可。

  • 相关阅读:
    【转载】RNA-seq测序方法
    NeuN神经元核抗原
    单细胞测序
    安装cytoscape时的折腾
    linux文件目录
    结合自己做过的数据,对cosmic signature理解
    减数分裂meiosis-有丝分裂miosis-染色体-DNA-等位基因
    AD发生了什么
    FDR的含义
    置换检验—结合GSEA解释
  • 原文地址:https://www.cnblogs.com/xyqCreator/p/2736637.html
Copyright © 2011-2022 走看看