C# 泛型

内容纲要

简介

泛型类和泛型方法兼具可重用性、类型安全性和效率,这是非泛型类和非泛型方法无法实现的。 泛型通常与集合以及作用于集合的方法一起使用。 System.Collections.Generic 命名空间包含几个基于泛型的集合类。本文主要介绍C# 泛型。

1、泛型

泛型将类型参数的概念引入 .NET,使用泛型类型可以最大限度地重用代码、保护类型安全性以及提高性能。泛型最常见的用途是创建集合类。.NET 类库在 System.Collections.Generic 命名空间中包含几个新的泛型集合类。 应尽可能使用这些类来代替某些类,如 System.Collections 命名空间中的 ArrayList

1)可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。

2)可以对泛型类进行约束以访问特定数据类型的方法。

3)在泛型数据类型中所用类型的信息可在运行时通过使用反射来获取。

2、定义使用泛型

型是为所存储或使用的一个或多个类型具有占位符(类型形参)的类、结构、接口和方法。 泛型集合类可以将类型形参用作其存储的对象类型的占位符;类型形参呈现为其字段的类型和其方法的参数类型。 泛型方法可将其类型形参用作其返回值的类型或用作其形参之一的类型。 下面看一下一个简单的泛型类定认:

例如:

  1. public class Generic<T>
  2. {
  3. public T Field;
  4. }

创建泛型类的实例时,指定用于替代类型形参的实际类型。 在类型形参出现的每一处位置用选定的类型进行替代,这会建立一个被称为构造泛型类的新泛型类。 将得到根据你选择的类型而定制的类型安全类。

例如:

  1. public static void Main()
  2. {
  3. Generic<string> g = new Generic<string>();
  4. g.Field = "A string";
  5. //...
  6. Console.WriteLine("Generic.Field = \"{0}\"", g.Field);
  7. Console.WriteLine("Generic.Field.GetType() = {0}", g.Field.GetType().FullName);
  8. }

3、泛型相关概念

1)泛型类型定义 是用作模板的类、结构或接口声明,带有可包含或使用的类型的占位符。 例如, System.Collections.Generic.Dictionary<TKey,TValue> 类可以包含两种类型:密钥和值。 由于泛型类型定义只是一个模板,所以你无法创建作为泛型类型定义的类、结构或接口的实例。

2)泛型类型参数(或 类型参数)是泛型类型或方法定义中的占位符。 System.Collections.Generic.Dictionary<TKey,TValue> 泛型类型具有两个类型形参 TKey 和 TValue,它们分别代表密钥和值的类型。

3)构造泛型类型(或 构造类型)是为泛型类型定义的泛型类型形参指定类型的结果。

4)泛型类型实参 是被泛型类型形参所替代的任何类型。

5)常见术语 泛型类型 包括构造类型和泛型类型定义。

6)借助泛型类型参数的 协变 和 逆变,可以使用类型自变量的派生程度比目标构造类型更高(协变)或更低(逆变)的构造泛型类型。 协变和逆变统称为“变体” 。 有关详细信息,请参阅协变和逆变。

7)约束 是对泛型类型参数的限制。 例如,你可能会将一个类型形参限制为实现 System.Collections.Generic.IComparer<T> 泛型接口的类型,以确保可对该类型的实例进行排序。 此外,你还可以将类型形参限制为具有特定基类、具有无参数构造函数或作为引用类型或值类型的类型。 泛型类型的用户不能替换不满足约束条件的类型实参。

4、泛型方法定义

泛型方法定义 是具有两个形参列表的方法:泛型类型形参列表和形参列表。 类型形参可作为返回类型或形参类型出现,例如:

  1. T Generic<T>(T arg)
  2. {
  3. T temp = arg;
  4. //...
  5. return temp;
  6. }

泛型方法可出现在泛型或非泛型类型中。 值得注意的是,方法不会仅因为它属于泛型类型或甚至因为它有类型为封闭类型泛型参数的形参而成为泛型方法。 只有当方法有属于自己的类型形参列表时才是泛型方法。 在以下代码中,只有方法 G 是泛型方法。

  1. class A
  2. {
  3. T G<T>(T arg)
  4. {
  5. T temp = arg;
  6. //...
  7. return temp;
  8. }
  9. }
  10. class Generic<T>
  11. {
  12. T M(T arg)
  13. {
  14. T temp = arg;
  15. //...
  16. return temp;
  17. }
  18. }

5、泛型约束

约束告知编译器类型参数必须具备的功能。 在没有任何约束的情况下,类型参数可以是任何类型。 编译器只能假定 System.Object 的成员,它是任何 .NET 类型的最终基类。 有关详细信息,请参阅使用约束的原因。 如果客户端代码使用不满足约束的类型,编译器将发出错误。 通过使用 where 上下文关键字指定约束。 下表列出了各种类型的约束:

注意:使用约束指定类型参数的功能和预期。 声明这些约束意味着你可以使用约束类型的操作和方法调用。 如果泛型类或方法对泛型成员使用除简单赋值之外的任何操作或调用 System.Object 不支持的任何方法,则必须对类型参数应用约束。

例如:

  1. public class Employee
  2. {
  3. public Employee(string name, int id) => (Name, ID) = (name, id);
  4. public string Name { get; set; }
  5. public int ID { get; set; }
  6. }
  7. public class GenericList<T> where T : Employee
  8. {
  9. private class Node
  10. {
  11. public Node(T t) => (Next, Data) = (null, t);
  12. public Node Next { get; set; }
  13. public T Data { get; set; }
  14. }
  15. private Node head;
  16. public void AddHead(T t)
  17. {
  18. Node n = new Node(t) { Next = head };
  19. head = n;
  20. }
  21. public IEnumerator<T> GetEnumerator()
  22. {
  23. Node current = head;
  24. while (current != null)
  25. {
  26. yield return current.Data;
  27. current = current.Next;
  28. }
  29. }
  30. public T FindFirstOccurrence(string s)
  31. {
  32. Node current = head;
  33. T t = null;
  34. while (current != null)
  35. {
  36. //The constraint enables access to the Name property.
  37. if (current.Data.Name == s)
  38. {
  39. t = current.Data;
  40. break;
  41. }
  42. else
  43. {
  44. current = current.Next;
  45. }
  46. }
  47. return t;
  48. }
  49. }

6、泛型委托

委托可以定义它自己的类型参数。 引用泛型委托的代码可以指定类型参数以创建封闭式构造类型,就像实例化泛型类或调用泛型方法一样

例如:

  1. public delegate void Del<T>(T item);
  2. public static void Notify(int i) { }
  3. Del<int> m1 = new Del<int>(Notify);

根据典型设计模式定义事件时,泛型委托特别有用,因为发件人参数可以为强类型,无需在它和 Object 之间强制转换。

例如:

  1. delegate void StackEventHandler<T, U>(T sender, U eventArgs);
  2. class Stack<T>
  3. {
  4. public class StackEventArgs : System.EventArgs { }
  5. public event StackEventHandler<Stack<T>, StackEventArgs> stackEvent;
  6. protected virtual void OnStackChanged(StackEventArgs a)
  7. {
  8. stackEvent(this, a);
  9. }
  10. }
  11. class SampleClass
  12. {
  13. public void HandleStackChange<T>(Stack<T> stack, Stack<T>.StackEventArgs args) { }
  14. }
  15. public static void Test()
  16. {
  17. Stack<double> s = new Stack<double>();
  18. SampleClass o = new SampleClass();
  19. s.stackEvent += o.HandleStackChange;
  20. }

 

C#

C# 系统应用之EM安全卫士总结及源码分享

2022-8-25 12:08:02

C#

C# 事件(event)

2022-8-25 17:09:57

0 条回复 A文章作者 M管理员
欢迎您,新朋友,感谢参与互动!
    暂无讨论,说说你的看法吧
个人中心
今日签到
私信列表
搜索