C#泛型编程指导原则_第1页
C#泛型编程指导原则_第2页
C#泛型编程指导原则_第3页
C#泛型编程指导原则_第4页
C#泛型编程指导原则_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Item1 Use Generic Collections 使用泛型集合使用泛型集合 数据集合是泛型最典型的应用之一 在你现存的代码里 可能已经遍布了 ArrayList 和 HashTable 在使用泛型之前 你可能会在将要编写的代码中大量使用 System Collection 这个 数据结构 然而 自从有了泛型 真的是没有任何理由再继续使用这个命名空间中的集合了 如果说仅仅有那么一个领域 泛型可以带来毫无疑问的价值的话 那么这个领域就是集合 如果没有泛型 非泛型集合的生产者和消费者将被迫把被包含的类型声明为 Objet 当然了 这样做的话 你的代码将会有很多强制转换和一般的类型转换 将每个 Object 对象转换为其真 实的类型 这将使代码变得很凌乱 同时也意味着对于值类型需要将其进行装箱才能表示为 Object 类型 即使在你努力的限制非泛型集合的影响的时候 一般你都会被迫进行对特定类型 的包装 从而使类膨胀 出于这些原因和其他一些在使用中的体会 可以很明确的得知 没有 任何理由倾向于这些老式的 非泛型的集合了 事实上 我想这样告诉大家 泛型集合是泛型 最引人入胜的用处 如果你并没有被使用泛型集合的价值所说服的话 那么泛型所带来的任何 其他好处也不能说服你 尽管我认为使用泛型的观点是不得不接受的 但是并不是每个解决方案都具有用泛型集合 完全取代与其相对应的非泛型集合的荣耀 如果你公开了一个 API 并且有客户绑定了非泛型 的 API 你就需要考虑如何将 API 转换成泛型的 在这种情况下 在具体实现中 加入泛型集 合到 API 中依然是值得的 Item 2 Replace Objects with Type Parameters 使使 用类型参数取代用类型参数取代 Object 类型类型 在使用泛型之前 程序员一般都依赖于 Object 类型来获得通用性 如果有这样一个类或 者方法 共性的功能 会被应用到不同的类型上 你将由很少的选择来处理 如果没有一个共 同的基类或者接口 仅有的方法就是使用通用的类型 Object 如 public object SendMsg object sender object param 当然 这样做是以牺牲类型安全为代价来换取的通用性 泛型为解决这种类型安全问题引入了一个完美的解决方法 通过使用泛型 可以在类型安 全和通用性之间得到平衡 上面的方法可以改成如下的模式 public K SendMsg I sender J param 这里来自经验的最基本的规则就是 在代码中应该尽量不使用 Object 类型 当遇到 Object 类型时 都应该先问问自己 泛型能否用在这里来减少对 Object 的依赖 Item 3 Replace System Type with Type Parameters 用类型参数取代用类型参数取代 System Type 在一些情况下 你可能在方法的签名中使用过System Type引用 以允许在基于支持的 特定类型的情况下 改变方法的行为 如 public object FindPerson Type personType int id 如果使用泛型 可以成为 public T FindPerson T personType int id 这样一来 接口将会更清晰 也可以减少方法实现的复杂性 同时意味着该方法的用户不 必强迫将该方法的返回值转换成指定的类型 Item 4 Use Type Parameters for Ref Types 对对 ref 类型使用类型参数类型使用类型参数 Item2 谈到了用类型参数替换 Object 类型的一般策略 该规则有一个变种 针对该变种引 入一个新的条款还是很有必要的 本条款的焦点在于 Object 类型的数据作为了引用参数 如 public void Sort ref object param1 ref object param2 一般的客户是这样使用该方法的 public void processItems Person person1 new Person 424 Person person2 new Person 190 Sort ref person1 ref person2 从表面上来看这样很好 Person 将被强制转换为 Object 类型 并传递给该方法 如果方法没有将参数指定为 ref 那么该方法也就没有什么问题了 然而使用了 ref 关键 字后 便一起将要求传入的参数类型与方法签名中指定的参数类型精确匹配 显然 这里的 Person 与 Object 不是精确匹配 因此 这样的话 可以通过将 Person 转换为 Object 来解决 但是 这样完全没有必要 通过泛型方法可以这样解决 public void Sort ref T param1 ref T param2 使用了泛型后 方法的类型就精确匹配了 在很多方面 该条款看起来是条款 2 的重复 然而 使用 ref 产生的复杂关系使得该条款 有单独存在的必要 类型引起变化的类型泛型化类型引起变化的类型泛型化 如果你通读以下自己代码中现存的类 方法 接口 委托 你会发现 自己一般会使用一 个类型所包含 管理的类型来定义它 在这些情况下 需要考虑是否要应用泛型 从而可以使一 个单独的实现就可以为多种数据类型提供服务 在这样的场景下应用泛型可以产生一系列的积 极作用 包括减少代码的大小 提高类型安全性等等 一 消除冗赘 的数据容器 迄今为止 数据容器是用来进行泛型重构的最通用 最直接的领域之一 大多数的解决方 案至少有一或两个这样的例子 为了向 ArrayList 的安全性妥协 你创建了自己的类型安全的 包装类 如 public class PersonCollection private ArrayList persons public PersonCollection persons new ArrayList public void Add Person person persons Add person public Person this int index get return Person persons index public class OrderCollection private ArrayList orders public OrderCollection orders new ArrayList public void Add Order order orders Add order public Order this int index get return Order orders index 这两个类封装了一个 ArrayList 向客户提供了一个类型安全的接口 他们是进行泛型重 构的极好候选者 这两个类 除了管理的数据类型不同外 就没有什么不同的了 通过使用泛型集合 Collection可以同时获得类型安全和上述两个类提供的功能性 具 体我们只要使用 Collection 和 Collection就行了 如果你的候选类提供的功能没有被 Collection所直接支持 只需要简单的创建一个 Collection的子类 在其中加入新的自定义成员就可以了 二 定义候选 方法 为了进行泛型重构而寻找候选方法 是很细小琐碎而又缺少精确性的科学 最常见的例子 就是 一些方法在整个对象上执行了相当基本的操作 没有调用任何特别的方法 如 public static void Swap ref String val1 ref String val2 String tmpObj val2 val2 val1 val1 tmpObj public static void Swap ref Double val1 ref Double val2 Double tmpObj val2 val2 val1 val1 tmpObj 如果有多个类型的数据要进行交换时 为了获得类型安全 避免对值类型进行装箱 需要 提供一系列的 overloaded 方法 如果使用 Object 类型作为参数的话 将引起一系列的问题 同时这样做也违背了条款 2 最好的方法就是使用泛型 如下所示 public static void Swap ref T val1 ref T val2 T tmpObj val2 val2 val1 val1 tmpObj 三 用一个泛 型委托替换多个委托 泛型委托的引入在根本上改变了应该在何时 如何创建自己的委托 委托代表了泛型最根 本 最自然的应用中的一种 如 非泛型委托是这样的 public delegate void MyDel1 int x string y public delegate void MyDel2 int x double y public delegate void MyDel3 int x long y public delegate void MyDel4 int x string y double z public delegate void MyDel5 int x double y double z 通过使用委托 可以使其大大简化 public delegate void MyDel T x U y public delegate void MyDel T x U y V z Item 6 Use Expressive Consistent Type Parameter Names 使用富有表现力的 前后一致的类型参数名使用富有表现力的 前后一致的类型参数名 称称 对于该问题 有两大基本阵营 一方认为 单个字母 的类型参数名称更好 因为它减少 了泛型声明的签名的大小 这是被大多数 C 模板库所使用的模式 另一方认为一个字母过于 简短 不足以表达类型参数的本质意义 他们希望用长一点的 更具有表述性的名字 用中国话最好来解释了 具体问题具体分析 在两种方法之间折中处理 下面的例子极好的表现了这一点 public class Dictionary public class Dictionary Item 7 Use Aliasing for Complex or Frequently Used Types 对复杂的或者频繁使用的类型 使用别名对复杂的或者频繁使用的类型 使用别名 简单的不需要解释 看例子 public void ProcessItem MyType1 value int status MyType1 x new MyType1 if status 1 MyType1 y value Else Nullable MyType1 z new Nullable MyType1 使用别名后可以简化为 using MType MyType1 public void ProcessItem MType value int status MType x new MType if status 1 MType y value else Nullable z new Nullable Item 8 Don t Use Constructed Types as Type Arguments 不要把构造类型作为类型参数不要把构造类型作为类型参数 虽然你拥抱了泛型的光彩 依然需要确保不要走极端 因为有可能在选择使用了泛型后 处理过程反而没有原本的优雅 如 public class MyComplexType public class MyType2 public class MyType3 public class TestClass public void foo MyComplexType MyType2 MyType3 x new MyComplexType MyType2 MyType3 从该例子可以看出 这样做极大的影响了程序的可读性 Item 9 Don t Use Too Many Type Parameters 不不 要使用太多的类型参数要使用太多的类型参数 一般来说 类型参数不要超过 2 个 因为使用的类型参数越多 就越难使用 维护和理解 Item 10 Prefer Type Inference with Generic Methods 优先使用泛型方法的类型推测优先使用泛型方法的类型推测 泛型方法的最帅的特性就是推测参数类型的能力 该特性可以消除为每个对泛型方法的调 用者显式提供参数类型的需要 这对整个代码的可维护性 可读性都有着显著的影响 如 public class TypeInference public void MyInferenceMethod I param1 J param2 public void MakeInferenceCall MyInferenceMethod TestVal 122 MyInferenceMethod 122 TestVal MyInferenceMethod new Order 833 22 上面使用了泛型方法的类型推测特性 这使得对泛型方法的调用变得透明了 这些调用看 起来和非泛型方法的调用没有区别 看起来就是是 overloaded 一样 Item 11 Don t Mix Generic and Non Generic Static Methods 不要混淆泛型静态方法与非泛型静态方法不要混淆泛型静态方法与非泛型静态方法 如果在泛型类中同时又有泛型静态方法与非泛型静态方法 就很容易造成混乱 如有这样一个类 public class TestClass public static void Foo public static void Foo 客户这样调用的话 TestClass Foo TestClass Foo 将产生很大的混乱 出现这种情况的处理方法很简单 修改方法名称 Item 12 Custom Collections Should Extend Collection自定义集合应当扩展自自定义集合应当扩展自 Collection 在一些时候 你很希望引入自己定义的泛型集合 典型来讲 自定义的泛型集合都应该由 现有的来 Collection扩展 这样就可以继承它的行为 并且可以根据自己特定的需要来补 充或者修改其功能 在这些情况下 你可能尝试使自定义泛型集合扩展自 List List毫无争议的是 System Collections Generic 命名空间中最强大最有活力的容器 然而 为了使其最优 该类 阻止客户重写 Overrid 或者改变它的行为 假设 你可以修改 List 类 使其可以在一个 Item 被添加或者被移除的时候记录一些额外的数据 但是 List不允许客户重写它的添加和移除 Item 的方法 因此 虽然 List可能是你最喜欢的类之一 但是它不能被作为自定义类的基 类 相反 Collection可以充当这一角色 虽然他并没有 List的所有能力 但是它公开 了一系列关键的保护成员 你可以自由的重写 Item 13 Use the Least Specialized Interface in Your APIs 在自己的在自己的 API 中使用最小的限定接口中使用最小的限定接口 在 System Collections Generic 命名空间中所包含的集合 实现了一系列不同的接口 这些接口为管理集合 与集合交互提供了不同层次的支持 在自己的 API 中 应该根据需要选 择最合适的接口 一条从经验中得来的规则就是 在自己的 API 中使用最小的限定接口 如 如果希望在集合中依次迭代集合中的 Item 仅仅需要实现 IEnumerable接口 Item 14 Enable for each Iteration with IEnumerable通过通过 IEnumerable来支持来支持 foreach 迭代迭代 System Collections Generic 命名空间包含了 IEnumerable 接口 该接口为迭代集合中的 元素提供了一个标准的机制 在框架中 它的角色比其他基于集合的接口更显著 foreach 提 供了一个简洁的 可读性强的途径来访问集合中的所有元素 Item 因此 在自己的泛型中最 好实现对 foreach 的支持 Item 15 Select the Least Restrictive Constraints 选择最少限制的约束选择最少限制的约束 在给类型参数选择约束条件的时候 最好只加入最少的限制 不要加入不必要的附加限制 下面是一个约束过头的例子 public interface IPerson void Validate public interface ICustomer IPerson public interface IEmployee IPerson public class TestClass where T ICustomer public TestClass T val val Validate 这个例子中有一个接口的继承 对 TestClass的约束是可行的 但是 但也过分的限制了参 数的类型 因为这里需要的约束是 Validate 而它是 IPerson 的一部分 所以你应该使用 IPerson 作为约束条件 Item 16 Don t Impose Hidden Constraints 不要强不要强 加隐式的约束条件加隐式的约束条件 即使你的类型没有在声明的时候包含任何约束 这并不意味着你的类型不能在实现中强加 隐式的约束 可以想象 通过强制转换或者调用 GetType 方法 可以在泛型类型中生成建立 于类型参数的代码 在这样的情况下 你仍然对类型参数强加了非直接的约束 仅仅是没有显 式的声明而已 这种隐式的约束当然是约束 同时是糟糕的主意 Item 17 Avoid Multiple Constraint Ambiguity 避避 免多重约束中的含糊免多重约束中的含糊 当使用约束的时候 可以选择对任何一个类型参数使用多重约束 事实上 你可以将单独 的类约束与多重接口约束联合使用 当你开始混合并匹配多重约束的时候 可能引入含糊不清 的约束 如 public interface I void Foo1 void Foo3 public class C public void Foo1 public class TestClass where T C I 这里接口 I 和类 C 中的 Foo1 产生了混淆 Item 18 Provide Parameterless Constructors 提提 供无参构造器供无参构造器 无论何时 当你引入自定义类型的时候 都需要考虑当他们被用作类型参数的时候会产生 什么样的行为 显然 你选择实现的接口会在该类型如何被约束方面起关键性的作用 至少 准备用为类型参数的每个类型都应该包含对参数构造的支持 通过支持这个约束 使得你的类 型可以被任何包含构造约束的泛型类型所支持 通过支持无参数的构造器来增加你的接口的价值的实例足够多 不过是对于泛型还是非泛 型解决方案 如果你曾经和工厂模式的任何一种变形打过交道 你可

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论