zoukankan      html  css  js  c++  java
  • 第四节:设计支持加载项的应用程序

    构建可扩展的应用程序时,接口是中心。可用基类来代替接口,但接口通常是首选的,因为它允许加载项开发人员选择他们自己的基类。例如,假如你要写一个应用程序,它能无缝的加载和使用别人创建的类型。下面描述了如何设计这样的应用程序。

    1. 创建一个“宿主SDK”(Host SDK)程序集,它定义了一个接口,接口的方法作为宿主应用程序和加载项之间的通信机制使用。为接口方法定义参数和返回值时,尝试使用MSCorLib.dll中定义的其他接口或类型。如果要传递并返回自己定义的数据类型,也在宿主的SDK程序集中定义他们。一旦搞定接口定义,就可以为这个程序集赋予一个强命名,然后把它打包并部署到合作伙伴和用户那里。一旦发布就应避免对程序集做出任何重大的改变。例如,不要以任何方式更改接口。但是,如果定义了任何数据类型,那么在类型中添加新成员时可以的。如果对程序集进行了任何修改,可能需要使用一个发布者策略文件来部署它。

    注意: 可以使用MSCorlib.dll中定义的类型,因为CLR总是加载与CLR版本匹配的那个版本的MSCorlib.dll。此外,在一个CLR实例中,只会加载一个版本的MSCorlib.dll。换言之,永远不会出现多个版本的MSCorlib.dll都加载的情况。最后的结果是,绝不会出现类型版本不匹配的情况。这还有助于减少应用程序对内存的需求。

    1. 当然,加载项开发人员会在他们自己的加载项程序集中定义自己的类型。他们的加载项程序集将引用你宿主程序集中的类型。加载项开发人员可以按他们的希望频率推出程序集的新版本,而宿主应用程序能够正确使用加载项的类型。不会出现任何问题。
    2. 创建一个单独的“宿主应用程序”程序集,在其中包含你应用程序的类型。这个程序集显然要引用“宿主SDK”程序集,并使用其中定义的类型。可自由修改“宿主应用程序”程序集中的代码。由于加载项开发人员不会引用这个“宿主应用程序”程序集,所以随时都能推出“宿主应用程序”程序集的版本,这样做并不会对加载项开发人员产生任何影响。

    本节包含了一些非常重要的信息。跨程序集使用类型时,需要关注程序集的版本控制问题。要花一些时间精心构造,将用于跨程序集边界通信的类型隔离到他们自己的程序集中。要避免以后更改这些类型的定义。但是,如果真的要修改类型的定义,一定要修改程序集的版本号,并为新版本的程序集创建一个发布者策略文件。

    下面看一个非常简单的例子,它综合运用了所有这些知识。首先是HostSDK程序集的代码:

    namespace HostSDK.dll
    {
    
        public interface IAddIn
        {
            string DoSomething(Int32 x);
        }
    
    }
    

      

    其次是AddInTypes.dll程序集中的代码,该程序集定义了两个公共类型,他们实现了HostSDK.dll的接口。为了生成这些程序集,必须引用HostSDK.dll程序集:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using HostSDK;
    
    
    namespace AddInTypes
    {
        public sealed class AddIn_A : IAddIn
        {
            public AddIn_A()
            { }
            public string DoSomething(Int32 x)
            {
                return "AddIn_A:" + x.ToString();
            }
        }
        public sealed class AddIn_B : IAddIn
        {
            public AddIn_B()
            { }
            public string DoSomething(Int32 x)
            {
                return "AddIn_B:" + x.ToString();
            }
        }
    }
    

      

    然后就是一个简单的Host.exe程序集(一个控制台应用程序)的代码。为了生成这个程序集,它必须引用HostSDK.dll程序集。为了发现有哪些可用的加载项类型,以下宿主代码假定类型是在一个以dll文件扩展名的程序集中定义的,而且这个程序集已经部署到和宿主的EXE相同的目录中。Microsoft的“托管可扩展性框架”时在我刚才描素的各种机制的顶部构建的,它提供了加载项注册和发现机制,构建动态可扩展性应用程序时,强烈建议你研究一下MEF,它能简化本章描素的一些操作。

            static void Main(string[] args)
            {
                String AddInDir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
                string[] AddInAssemblies = Directory.GetFiles(AddInDir, "*.dll");
                List<Type> AddInTypes = new List<Type>();
                foreach (String file in AddInAssemblies)
                {
                    Assembly AddInAssembly = Assembly.LoadFrom(file);
                    foreach (Type t in AddInAssembly.GetExportedTypes())
                    {
                        //如果类型实现了IAddIn接口的一个类,该类就可以为宿主使用
                        if (t.IsClass && typeof(IAddIn).IsAssignableFrom(t))
                        {
                            AddInTypes.Add(t);
                        }
                    }
                }
                foreach (Type t in AddInTypes)
                {
                    IAddIn ai = (IAddIn)Activator.CreateInstance(t);
    
                    Console.WriteLine(ai.DoSomething(5));
                }
            }
    

      

    这个简单的宿主和加载项例子没有用到AppDomain。但在实际应用程序中,可能在每个加载项自己的AppDomain中创建他们,每个AppDomain都有自己的安全性和配置设置。当然,如果将加载项从内存中移除,可以卸载相应的AppDomain。为了跨AppDomain边界通信,可告诉加载项开发人员从MashalByRefObject派生出他们自己的加载项类型。但是,另一个更常见的版本是让宿主应用程序定义自己的、从MashalByRefObject派生的内部类型。每个AppDomain创建好之后,宿主要在新的APPdomain中创建他们自己的MashalByRefObject派生类的实例。宿主的代码(位于默认AppDomain中)将和它自己的类型(位于其他AppDomain)通信,让后者载入加载项程序集,并创建和使用加载项程序集。

  • 相关阅读:
    第6章 静态路由和动态路由(2)_路由汇总和默认路由
    第6章 静态路由和动态路由(1)_静态路由
    第5章 IP地址和子网划分(4)_超网合并网段
    第5章 IP地址和子网划分(3)_子网划分
    第5章 IP地址和子网划分(2)_IP地址分类和NAT技术
    第5章 IP地址和子网划分(1)_IP格式和子网掩码
    第4章 数据链路层(5)_高速以太网
    第4章 数据链路层(4)_扩展以太网
    第4章 数据链路层(3)_广播信道的数据链路
    第4章 数据链路层(2)_点到点信道的数据链路
  • 原文地址:https://www.cnblogs.com/bingbinggui/p/4575633.html
Copyright © 2011-2022 走看看