详解c# 泛型类的功能

  在泛型类中,由于不知道泛型参数T是什么类型,可能是引用类型,也可能是值类型,因此不能将null等赋予泛型类型。如何对泛型对象赋初值、如何保证泛型的正确性等,以使用泛型文档管理器为例:

  文档管理器用于从队列中读写文档。首先创建一个泛型管理器AddDocument()方法添加一个文档到队列中,IsDocumentAvailabe只读属性指示队列中是否还有文档。

public class DocumentManager<T>
{
  private readonly Queue<T> documentQueue = new Queue<T>();

  public void AddDocument(T doc)
  {
    lock (this)
    {
      documentQueue.Enqueue(doc);
    }
  }

  public bool IsDocumentAvailable
  {
    get { return documentQueue.Count > 0; }
  }
}

1、默认值

  给DocumentManager<T>类添加一个GetDocument()方法,该方法以返回队列中的一个文档。如果队列中存在文档,则返回一个文档;如果队列中已没有文档,则返回默认值。但是,对于泛型T,不能将null赋予T的对象,因为无法确定它是引用类型还是值类型。在C#中,为我们提供了一个default关键字,泛型T的对象赋予默认值,如:引用类型为null、值类型int等为0……

public T GetDocument()
{
  T doc = default(T);
  lock (this)
  {
    if (documentQueue.Count > 0)
    {
      doc = documentQueue.Dequeue();
    }
  }
  return doc;
}

2、约束

  如果泛型类需要调用泛型类型中的方法,那么必须对泛型添加约束。否则,不能确保声明的泛型类型实现了对应的类型,具有相关方法。创建文档类Document,其实现了接口IDocument:

public interface IDocument
{
  string Title { get; set; }
  string Content { get; set; }
}

public class Document : IDocument
{
  public Document()
  {
  }

  public Document(string title, string content)
  {
    this.Title = title;
    this.Content = content;
  }

  public string Title { get; set; }
  public string Content { get; set; }
}

  给泛型文档管理器DocumentManager<T>添加方法DisplayAllDocuments(),使得队列中所有文档的标题能展示出。在展示文档标题前,将类型T强制转换为IDocumnet接口,以显示标题:

public void DisplayAllDocuments()
{
  foreach (T doc in documentQueue)
  {
    Console.WriteLine((doc as IDocument).Title);//强制转换
  }
}

  但是,如果类型T没有实现接口IDocument,在对类型进行强制转换时就会出现一个异常。如果对方法添加rty……catch处理,将非常损耗性能。同样的,即使类型实现了接口IDocument,在进行转换时也会出现性能的损耗。

  那么,如果能对泛型TDocument进行约束,使得泛型类型必须实现接口IDocument,则不会出现对类型进行强制转换时的异常。甚至不需要强制转换,性能也将得到优化。因此,前面的泛型文档管理器改写为(前面的T,改写为TDocument,以此暗示是文档类型):

public class DocumentManager<TDocument>
  where TDocument : IDocument
{
   //……
}

  对于实现了约束的泛型文档管理器,可以处理任何实现了IDocument接口的类。其DisplayAllDocuments()方法改写为:

public void DisplayAllDocuments()
{
  foreach (TDocument doc in documentQueue)
  {
    Console.WriteLine(doc.Title);
  }
}

  在其他地方调用时,可以用Document类型实例化泛型类型DocumentManager<TDocument>。因为Document实现了接口IDocument:

static void Main()
{
  var dm = new DocumentManager<Document>();
  dm.AddDocument(new Document("Title A", "Sample A"));
  dm.AddDocument(new Document("Title B", "Sample B"));

  dm.DisplayAllDocuments();

  if (dm.IsDocumentAvailable)
  {
    Document d = dm.GetDocument();
    Console.WriteLine(d.Content);
  }
}

  泛型类型支持的几种约束:struct(结构约束,类型T必须是值类型)、class(类约束,类型T必须是引用类型)、IFoo(类型T必须实现接口IFoo)、new()(构造函数约束,类型T必须有一个无参构造函数)、TOther(类型T派生自TOther,也称“裸类型约束”)。

  泛型约束中:

  • 只能为无参构造函数定义构造约束,不能为有任何参数的构造函数定义构造函数约束。
  • 泛型可以有多个约束。如:public class DocumentManager<TDocument> where TDocument : IDocument,new()。
  • where不能定义必须由泛型类型实现的运算符

3、继承

  泛型类也可以实现继承,如Queue<T>里,继承实现了接口IEnumerable<T>接口。泛型类型可以实现泛型接口,也可以派生自一个类。泛型类型可以派生自泛型基类:

class Base<T>
{
  //...............
}

class Derived<T>:Base<T>
{
  //...............
}

  派生类可以是泛型类,也可以是非泛型类型:

abstract class Calc<T>
{
  public abstract T Add(T x, T y);
  public abstract T Sub(T x, T y);
}

class IncCalc: Calc<int>
{
  public override int Add(int x, int y)
  {
    return x + y;
  }
  public override int Sub(int x, int y)
  {
    return x - y;
  }
}
class DoubleCalc : Calc<double>
{
  public override double Add(double x, double y)
  {
    return x + y;
  }
  public override double Sub(double x, double y)
  {
    return x - y;
  }
}

4、静态成员

  泛型类的静态成员只能在一个实例中共享:

class StaticDemo<T>
{
  public static string Type;
}

static void Main()
{
  StaticDemo<int>.Type = "int类型";
  StaticDemo<object>.Type = "Object类型";
  Console.WriteLine(StaticDemo<int>.Type);//输出:int类型
}

  实际上,每当用一个类型去代替泛型中的T时,都是在创造一个实例类型。因此,泛型类型中的静态字段,会在不同的类型替代泛型T的实例中重新生成。这样设计也有好处,可以为程序提供一个“泛型缓存”的概念,使用泛型的静态成员,使它存放在缓存中,方便调用。

以上就是详解c# 泛型类的功能的详细内容,更多关于c# 泛型类的资料请关注我们其它相关文章!

(0)

相关推荐

  • 深入浅析C#泛型类型

    上篇文章给大家介绍了浅析C# 中的类型系统(值类型和引用类型),接下来通过本文给大家介绍下c# 泛型类型, 说下C#中的泛型,熟练地使用泛型能提高代码的重用性,使用我们代码瞬间就高大上了,当然只有一点点,真的只有一点点,因为后面要学习和掌握的知识还有很多.先来看下一个使用Dictionary<TKey,TValue>的例子. static void Main(string[] args) { Dictionary<int, string> result = GetAll(); }

  • c#自定义泛型类的实现

    闲来无事,自己研究了泛型类的简单的使用,where表示泛型约束,表示泛型类型中的参数只能是car类型,IEnumerable是一个接口,一个集合要支持FOREAch遍历,必须实现IEnumerable接口 复制代码 代码如下: public class Car    {        public string PetName;        public int Speed;        public Car(string name, int currentSpeed)        {  

  • 深入解析C#中的泛型类与泛型接口

    泛型类 泛型类封装不是特定于具体数据类型的操作.泛型类最常用于集合,如链接列表.哈希表.堆栈.队列.树等.像从集合中添加和移除项这样的操作都以大体上相同的方式执行,与所存储数据的类型无关. 对于大多数需要集合类的方案,推荐的方法是使用 .NET Framework 类库中所提供的类. 一般情况下,创建泛型类的过程为:从一个现有的具体类开始,逐一将每个类型更改为类型参数,直至达到通用化和可用性的最佳平衡.创建您自己的泛型类时,需要特别注意以下事项: 将哪些类型通用化为类型参数. 通常,能够参数化的

  • .NET/C#如何判断某个类是否是泛型类型或泛型接口的子类型详解

    前言 泛型:通过参数化类型来实现在同一份代码上操作多种数据类型.利用"参数化类型"将类型抽象化,从而实现灵活的复用.在.NET类库中处处都可以看到泛型的身影,尤其是数组和集合中,泛型的存在也大大提高了程序员的开发效率.更重要的是,C#的泛型比C++的模板使用更加安全,并且通过避免装箱和拆箱操作来达到性能提升的目的.因此,我们很有必要掌握并善用这个强大的语言特性. C#泛型特点: 1.如果实例化泛型类型的参数相同,那么JIT编辑器会重复使用该类型,因此C#的动态泛型能力避免了C++静态模

  • C#泛型类型知识讲解

    概述 泛型类和泛型方法兼具可重用性.类型安全性和效率,这是非泛型类和非泛型方法无法实现的 泛型通常与集合以及作用于集合的方法一起使用 泛型所属命名空间:System.Collections.Generic 可以创建自定义泛型接口.泛型类.泛型方法.泛型事件和泛型委托,以提供自己的通用解决方案,设计类型安全的高效模式 泛型允许编写一个可以与任何数据类型一起工作的类或方法 示例 using System; using System.Collections.Generic; namespace Gen

  • C#泛型类创建与使用的方法

    本文实例为大家分享了C#泛型类创建与使用的具体代码,供大家参考,具体内容如下 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication13 { class Program { static void Main(string[] args) { Test<string,int> t = new Test<string,i

  • C#中利用LINQ to XML与反射把任意类型的泛型集合转换成XML格式字符串的方法

    在工作中,如果需要跟XML打交道,难免会遇到需要把一个类型集合转换成XML格式的情况.之前的方法比较笨拙,需要给不同的类型,各自写一个转换的函数.但是后来接触反射后,就知道可以利用反射去读取一个类型的所有成员,也就意味着可以替不同的类型,创建更通用的方法.这个例子是这样做的:利用反射,读取一个类型的所有属性,然后再把属性转换成XML元素的属性或者子元素.下面注释比较完整,就话不多说了,有需要看代码吧! using System; using System.Collections.Generic;

  • 详解C# 泛型中的数据类型判定与转换

    提到类型转换,首先要明确C#中的数据类型,主要分为值类型和引用类型: 1.常用的值类型有:(struct) 整型家族:int,byte,char,short,long等等一系列 浮点家族:float,double,decimal 孤独的枚举:enum 孤独的布尔:bool 2.常用的引用类型有: string,class,array,delegate,interface 值得注意的是,无论是值类型还是引用类型,在C#中都派生于object,没错,这家伙就是万恶之源! 正是因为有了这一特性,于是我

  • Java泛型类型通配符和C#对比分析

    c#的泛型没有类型通配符,原因是.net的泛型是CLR支持的泛型,而Java的JVM并不支持泛型,只是语法糖,在编译器编译的时候都转换成object类型 类型通配符在java中表示的是泛型类型的父类 public void test(List<Object> c) { for(int i = 0;i < c.size();i++) { System.out.println(c.get(i)); } } //创建一个List<String>对象 List<String&g

  • 详解C#泛型的类型参数约束

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

随机推荐