c#

位置:IT落伍者 >> c# >> 浏览文章

第十三讲:关于.NET组件


发布日期:2019年09月16日
 
第十三讲:关于.NET组件

NET组件是什么

组件的定义有多种但最常见有几种组件是可互换的软件部分它既是工业化系统的产物也是工业第系统的动力NET平台的组件层中组件是以Assemblies的形式创建的

NET平台创建了组件并将组件作为其基本的元素从本质上看NET平台组件是一个用任何NET语言以插件形式开发的可互换的软件部件它可以与其他应用程序实现互操作使用COM+服务的NET组件被称作服务化组件以示与NET中标准的可管理组件的区别

强命名NET组件

下面我们将讨论强命名组合体(NET组件)是什么当开发可配置类时它必须被编译在编译代码后有二方面的事情需要考虑第一COM+集成要求被编译的组合体必须被强命名我们必须通过运行被称为snexe的强命名工具生成一个密码以生成一个强命名的组合体一旦编译了强命名的组合体必须使用SystemReflection名字空间中一个被称作AssemblyKeyFileAttribute的组合体级的属性调用存储在文件中的该密码

#using  

using System;

using System::EnterpriseServices;

using System::Reflection;

[assembly: ApplicationName(FirstApp)]

[assembly: ApplicationActivation(ActivationOptionLibrary)]

// AssemblyKeyFile属性调用由snexe生成的密码文件组合体将拥有强命名

[assembly: AssemblyKeyFile(thiskeyfile)]

namespace ESExample

{

???

}

第二在编译强命名的组合体时必须调用输出SystemEnterpriseServices名字空间中类型的组合体━━SystemEnterpriseServicesdll下面是生成密码和编译可配置类的命令

sn k thiskeyfile

Cl /out:ThisExampledll /t:library

/r:SystemEnterpriseServicesdll FirstCfgClasscpp

在COM+中注册NET组件

COM+有二种注册方式动态方式和手工方式这二种方式都相当简单但对于本例动态方式是合适的动态注册方式还有一些要求

组合体必须是强命名的

组合休可以不在全局性的组合体缓沖区中

组合体必须被可管理的(NET)客户端使用

组合体激活类型必须是Library

初看起来似乎限制相当严格但其实它包括多种情况读者一定在想激活类型必须是Library但还没有创建过Library COM+组件呢NET中服务组件的客户端在同一台计算机上或者客户端将远程访问代理应用程序以访问COM+组件因此NET解决方案将在大多数情况下使用动态注册方式

在客户端第一次实例化服务化组件时就会进行动态注册而且对于每个版本的组合体而言只会注册一次我们需要注意COM+目录更新和组件第一次被访问之间在时间上的滞后代码将跟蹤内存中对象的数量以及在一定的活动期间及其之后仍然有多少对象仍然是活动的

注意在对对象进行初次调用后系统中存在一个有个对象的缓沖池似乎是一旦一个对象被实例化在有方法被调用之前它一直是活动的一旦有方法被调用该对象就只在调用期间是活动的这也提醒我们在准备使用对象之前尽量不要去招惹它们

移植的策略

在决定将部分或全部现有的应用软件移植到NET环境中就需要决定哪种移植方法最适合你本篇文章介绍了水平移植和垂直移植二种应用软件的移植方式

水平移植和垂直移植

水平移植是指取代应用程序中的全部一个层例如可以选择取代基于Web的表示层中的ASP代码或选择取代中间层中的COM代码垂直移植指的是替换一个应用程序中所有n层中的一部分

组件设计

本篇文章提出了一些与向NET/COM移植和组件设计互操作性问题方面的普遍原则通过互操作层在NET和 COM环境之间进行互操作时CCW或RCW(依据调用的方向而不同)必须在二个环境之间的调用栈中对数据进行转化有些数据类型无需转换包括整型长整型和浮点型数据类型在内的通用性数据无需转换而非通用性数据则需要转换

Visual Basic的BSTR是非通用性数据类型的一个例子在向NET移植应用程序之前应该在可管理性和非可管理性代码之间尽量少地使用非通用性数据类型原因是相关的转换代价将影响到应用程序的性能

通用数据类型

大多数的数据类型在可管理性和非可管理性内存中的表示都相同互操作层无需作特别的处理由于在可管理和非可管理代码之间无需转换因此这些数据类型被称作通用类型整型和浮点型数据是通用类型数据类型由通用型数据类型组成的数组和结构也是通用型数据类型

非通用数据类型

非通用数据类型在可管理和非可管理语言中的表示是不同的由于当在可管理性和非可管理性代码之间进行互操作时它们要求互相转换因此被称作非通用型数据类型例如由于有几种不同的非可管理性表示其中的一些可能需要进行转换因此可管理的字符串是非通用型数据类型字符串日期对象是非通用型数据类型的例子在执行互操作时它们都需要转换

现有的COM组件和可管理客户端

在向NET平台移植应用程序时需要考虑现有的COM组件所使用的界面尽管会不再使用现有的COM客户端仍然会在NET客户端中使用现有的COM组件因此在设计界面时应该如何既考虑到二种环境中现有的组件也要考虑到未来的可管理客户端

在向NET移植组件时需要使用tlbimp工具自动地生成一个应用程序的RCW缺省情况下RCW使用与现有组件相同的界面(通过定义相同和属性和方法)在许多情况下传统的COM类型的界面并不是天生地从可管理性代码中使用的可管理性代码开发人员将能够充分地利用下面的特性

·参数化的构造器

·继承

·静态方法

我们应当考虑编写一个COM对象使用的自定义包装类向可管理客户端提供这些能力创建更适合可管理代码环境的界面包装类在内部使用COM组件的RCW并代理对现有COM组件的大多数调用一些调用能够完成更复杂的数据类型转换工作例如ADO NET数据集和ADO记录集之间的映射此后我们可以将更多的功能从COM组件转移到包装类中而不会影响可管理代码在决定是使用RCW或自定义的可管理性包装类时有许多因素需要考虑需要注意的是TlbImp工具能够将COM类型库转换为NET架构元数据一旦类型库被转换为元数据可管理客户端可以无缝地调用COM类型为了简化使用我们总是在类型库中提供类型信息

如果组件有大量的已经习惯了现有对象模型的客户端创建RCW和使用现有的界面就是一个比较合适的策略Excel中的对象模型被使用VBA的Excel开发人员广泛使用对象模型是高度结构化的并且能够很好地映射由Excel提供的特性和用户界面客户非常熟悉现有的对象模型如果对象模型发生大幅度的变化用户就需要进行大量的训练在本例中使用标准的RCW可能是合适的

在编写COM界面的自定义的可管理包装类时这些界面将被通过RCW从可管理性代码中调用每个属性调用都需要有互操作层的参与会带来一定的代价对于一个只作很少工作的简单界面来说互操作造成的代价将是条汇编指令对于完成大量工作的方法而言这点代价是微不足道的但对于一个简单的属性访问而言这一代价还是太大了

如果在不久之后要将COM组件的客户端移植到NET平台上在考虑编写自定义的可管理包装类时应当将界面的功能由COM组件转到包装类中否则可以在COM对象中实现界面并被代理到可管理的包装类中

通过重新安排代码我们能够使互操作层的代价最小并拥有一个从可管理代码到对象的最简单自然的界面编写自定义的可管理包装类的带来的另一个好处是可以移动远程对象的分界线

类的界面的实现

在可管理代码中类的界面的定义并不是显性的该界面包含适用于NET对象使用的所有公共方法属性域和事件它可以是一个双重或者仅起调度作用的界面类界面的名字为NET类名字前加一下划线例如对于Mammals而言类界面的名字是_Mammals对于派生类而言类界面也需要实现基本类所有的公共方法域和属性派生类还实现每个基本类的界面例如Mammals类扩展了类MammalMainclassNET对象向COM客户端提供三个名字为_Mammals_MammalMainclass和_Object的界面

COM客户端能够获得名字为Mammals的类界面该界面定义在由类型库输出向导(Tlbexpexe)工具生成的类型库中如果Mammals类实现一个或多个界面这些界面将出现在coclass中

[odl uuid() hidden dual nonextensible oleautomation]

interface _Mammals : IDispatch

{

[id(x) propget] HRESULT ToString([out retval] BSTR*

pRetVal);

[id(x)] HRESULT Equals([in] VARIANT obj [out retval]

VARIANT_BOOL* pRetVal);

[id(x)] HRESULT GetHashCodes([out retval] short* pRetVal);

[id(x)] HRESULT GetType([out retval] _Type** pRetVal);

[id(xd)] HRESULT EatIt();

[id(xe)] HRESULT GetBreathe();

[id(xf)] HRESULT GoSleep();

}

[uuid()]

coclass Mammals  

{

[default] interface _Mammals;

}

类界面生成是可选的如果没有选择其他选项COM互操作层为每个输出到类库中的类生成一个只起调度作用的界面通过在类中添加ClassInterfaceAttribute属性我们可以中止或修改这一界面的自动创建尽管类界面能够使我们无须向COM提供可管理               

上一篇:.Net里的哈希表和串行化的简单介绍

下一篇:在.Net程序中使用log4net记录日志