Effective C#原则42:使用特性进行简单的反射

当你创建了一个与反射相关的系统时,你应该为你自己的类型,方法,以及 属性定义一些自己的特性,这样可以让它们更容易的被访问。自定义的特性标示 了你想让这些方法在运行时如何被使用。特性可以测试一些目标对象上的属性。 测试这些属性可以最小化因为反射时可能而产生的类型错误。

假设你须 要创建一个机制,用于在运行时的软件上添加一个菜单条目到一个命令句柄上。这个须要很简单:放一个程序集到目录里,然后程序可以自己发现关于它的一些 新菜单条目以及新的菜单命令。这是利用反射可以完成的最好的工作之一:你的 主程序须要与一些还没有编写的程序集进行交互。这个新的插件同样不用描述某 个集合的功能,因为这可以很好的用接口来完成编码。

让我们为创建一 个框架的插件来开始动手写代码吧。你须要通过Assembly.LoadFrom() 函数来加 载一个程序,而且要找到这个可能提供菜单句柄的类型。然后须要创建这个类型 的一个实例对象。接着还要找到这个实例对象上可以与菜单命令事件句柄的申明 相匹配的方法。完成这些任务之后,你还须要计算在菜单的什么地方添加文字,以及什么文字。

特性让所有的这些任务变得很简单。通过用自己定义的 特性来标记不同的类以及事件句柄,你可以很简单的完成这些任务:发现并安装 这些潜在的命令句柄。你可以使用特性与反射来协作,最小化一些在原则43中描 述的危险事情。

第一个任务就是写代码,发现以及加载插件程序集。假 设这个插件在主执行程序所在目录的子目录中。查找和加载这个程序集的代码很 简单:

// Find all the assemblies in the Add-ins directory:
string AddInsDir = string.Format( " {0}/Addins",
 Application.StartupPath );
string[] assemblies = Directory.GetFiles( AddInsDir, "*.dll" );
foreach ( string assemblyFile in assemblies )
{
 Assembly asm = Assembly.LoadFrom( assemblyFile );
 // Find and install command handlers from the assembly.
}

接下来,你须要 把上面最后一行的注释替换成代码,这些代码要查找那些实现了命令句柄的类并 且要安装这些句柄。加载完全程序集之后,你就可以使用反射来查找程序集上所 有暴露出来的类型,使用特性来标识出哪些暴露出来的类型包含命令句柄,以及 哪些是命令句柄的方法。下面是一个添加了特性的类,即标记了命令句柄类型:

// Define the Command Handler Custom Attribute:
[AttributeUsage( AttributeTargets.Class )]
public class CommandHandlerAttribute : Attribute
{
 public CommandHandlerAttribute( )
 {
 }
}

这个 特性就是你须要为每个命令标记的所有代码。总是用AttributeUsage 特性标记 一个特性类,这就是告诉其它程序以及编译器,在哪些地方这个特性可以使用。 前面这个例子表示CommandHandlerAttribute只能在类上使用,它不能应用在其 它语言的元素上。

你可以调用GetCustomAttributes来断定某个类是否具 有CommandHandlerAttribute特性。只有具有该特性的类型才是插件的候选类型 :

// Find all the assemblies in the Add-ins directory:
string AddInsDir = string.Format( "{0}/Addins", Application.StartupPath);
string[] assemblies = Directory.GetFiles( AddInsDir, "*.dll" );
foreach ( string assemblyFile in assemblies )
{
 Assembly asm = Assembly.LoadFrom( assemblyFile );
 // Find and install command handlers from the assembly.
 foreach( System.Type t in asm.GetExportedTypes( ))
 {
  if (t.GetCustomAttributes (
   typeof( CommandHandlerAttribute ), false ).Length > 0 )
  {
   // Found the command handler attribute on this type.
   // This type implements a command handler.
    // configure and add it.
  }
  // Else, not a command handler. Skip it.
 }
}

时间: 2024-08-02 16:31:36

Effective C#原则42:使用特性进行简单的反射的相关文章

Effective C#原则43:请勿滥用反射

创建二进制的组件时,同时也意味着你要使用迟后绑定和反射来查找你所须 要的具有特殊功能代码.反射是一个很有力的工具,而且它让你可以写出可动态 配置的软件.使用反射,一个应用程序可以通过添加新的组件来更新功能,而这 些组件是在软件最开始发布时没有的.这是有利的. 这一伸缩性也带来 了一些复杂的问题,而且复杂问题的增加又会增加出现其它问题的可能.当你使 用反射时,你是围绕着C#的安全类型.然而,成员调用的参数和返回值是以 System.Object类型存在的.你必须在运行时确保这些类型是正确的.简单的

Effective C#原则48:了解更多的工具和资源

对于C#以及.Net来说这是激动人心的时候.这些工具目前还是比较新的,整 个社区都在学习如何使用这些工具.一些资源可以帮助你提高你的知识,以及为 .Net和C#创建一个更大的知识社区.这些工具是我每天都向C#开发人员推荐的. 关于C#实践的全部内容还在写作当中,跟进它们而且不断了解相关的内容. 第一个应该在每一个C#开发人员的工具箱的工具是NUnit, 它可以在 www.nunit.org网站上找到.NUnit是一个自动进行单元测试的工具,功能和 JUnit很像.和其它大多数开发人员一样,我讨厌

Effective C#原则31:选择小而简单的函数

做为一个有经验的程序员,不管你在使用C#以前是习惯用什么语言的,我们 综合了几个可以让你开发出有效代码的实际方法.有些时候,我们在先前的环境 中所做的努力在.Net环境中却成了相反的.特别是在你试图手动去优化一些代码 时尤其突出.你的这些行为往往会阻止JIT编译器进行最有效的优化.你的以性 能为由的额外工作,实际上产生了更慢的代码.你最好还是以你最清楚的方法写 代码,其它的让JIT编译器来做.最常见的一个例子就是预先优化,你创建一个 很长很复杂的函数,本想用它来避免太多的函数调用,结果会导致很多

Effective C#原则25 让你的类型支持序列化

对象的持久是类型的一个核心功能.这是一个在你忽略对它的支持以前,没 有人会注意到的基本元素之一. 如果你的类型不能恰当的支持序列化,那么对 于把你类的做为基类或者成员的开发人员来说,你会给他们增加很多的工作量. 当你的类型不支持序列化时,他们不得不围绕这工作,自己添加实现这个标准的 功能.而对于不能访问类的私有成员的开发人来说,恰当的实现你的类型的序列 化是不太可能的.如果你的类型不支持序列化,那么对于你的用户来说,想再要 实现实它是很困难或者根本就不可能的事. 取而代之的是,为你的实际 类型添

Effective C#原则24:选择申明式编程而不是命令式编程

与命令式编程相比,申明式编程可以用更简单,更清楚的方法来描述软件的 行为.申明式编程就是说用申明来定义程序的行为,而不是写一些指令.在C#里 ,也和其它大多数语言一样,你的大多数程序都是命令式的:在程序中写一个方 法来定义行为.在C#中,你在编程时使用特性就是申明式编程.你添加一个特性 到类,属性,数据成员,或者是方法上,然后.Net运行时就会为你添加一些行为 .这样申明的目的就是简单易用,而且易于阅读和维护. 让我们以一个 你已经使用过的例子开始.当你写你的第一个ASP.Net Web服务时,

Effective C#原则47:选择安全的代码

.Net运行时已经设计好了,一些怀有恶意的代码不能渗透到远程计算机上并 执行.目前一些分部式系统依懒于从远程机器上下载和执行代码.如果你可以通 过Internet或者以太网来发布你的软件,或者直接从web上运行,但你须要明白 CRL在你的程序集中的一些限制.如果CLR不是完全相信一个程序集,它会限制一 些的行为.这些调用代码要有访问安全认证(CAS).从另一方面来说,CLR强制要 求基于角色的安全认证,这样这些代码才能或者不能在基于一个特殊的角色帐号 下运行. 安全违例是运行时条件,编译器不能强

Effective C#原则45:选择强异常来保护程序

当你抛出异常时,你就在应用程序中引入了一个中断事件.而且危机到程序 的控制流程.使得期望的行为不能发生.更糟糕的是,你还要把清理工作留给最 终写代码捕获了异常的程序员.而当一个异常发生时,如果你可以从你所管理的 程序状态中直接捕获,那么你还可以采取一些有效的方法.谢天谢地,C#社区不 须要创建自己的异常安全策略,C++社区里的人已经为我们完成了所有的艰巨的 工作.以Tom Cargill的文章开头:"异常处理:一种错误的安全感觉, " 而且Herb Sutter,Scott Meyer

Effective C#原则40:根据需求选择集合

"哪种集合是最好的?"答案是:"视情况而定." 不同的集合有不同的性能,而且在不同的行为上有不同的优化..Net框架支持很 多类似的集合:链表,数组,队列,栈,以及其它的一些集合.C#支持多维的数 组,它的性能与一维的数组和锯齿数组都有所不同..Net框架同样包含了很多特 殊的集合,在你创建你自己的集合类之前,请仔细参阅这些集合.你可以发现很 多集合很快,因为所有的集合都实现了ICollection接口.在说明文档中列出了 所有实现了ICollection接口的集合

Effective C#原则37:使用标准的配置机制

我们要寻求一种避免直接写代码的应用程序配置和信息设置方法,我们已经 创建了多种不同的策略来存储配置信息.而我们是要寻求一种正确的方法,我们 要不断提高和改我们的想法,关于哪里是放置这些信息的好地方.INI文件?这 是Windows3.1做的事,配置信息的结构是受限制的,而且在文件名上可能还会与 其它程序程序相冲突.注册表?是的,是这个正确的想法,但它也有它的限制. 乱七八糟的程序可能会通过在注册表里写一些错误信息来严重破坏计算机.正因 为写注册表存在危险,一个应用程序必须有管理员权限来写注册表的