详解c# 泛型类的功能

 更新时间:2020年10月30日 15:08:56   作者:一只独行的猿  
这篇文章主要介绍了c# 泛型类的功能,帮助大家更好的理解和学习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# 泛型类的资料请关注脚本之家其它相关文章!

相关文章

  • C#贪吃蛇游戏实现分析

    C#贪吃蛇游戏实现分析

    这篇文章主要为大家分析了C#贪吃蛇游戏的实现代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • C#生成饼形图及添加文字说明实例代码

    C#生成饼形图及添加文字说明实例代码

    这篇文章主要介绍了C#生成饼形图及添加文字说明的方法,非常实用的功能,需要的朋友可以参考下
    2014-07-07
  • 通俗易懂的C#之反射教程

    通俗易懂的C#之反射教程

    这篇文章主要介绍了通俗易懂的C#之反射教程,本文深入分析了反射内部的原理,剖析了内部属性、方法的运作,并用通俗易懂的语言阐述,需要的朋友可以参考下
    2015-01-01
  • C#中Lambda表达式的三种写法

    C#中Lambda表达式的三种写法

    这篇文章介绍了C#中Lambda表达式的三种写法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • C#判断某程序是否运行的方法

    C#判断某程序是否运行的方法

    这篇文章主要介绍了C#判断某程序是否运行的方法,代码结构简单功能实用,需要的朋友可以参考下
    2014-09-09
  • Unity UGUI的EventSystem事件系统组件介绍使用

    Unity UGUI的EventSystem事件系统组件介绍使用

    这篇文章主要为大家介绍了Unity UGUI的EventSystem事件系统组件介绍使用,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • c#序列化详解示例

    c#序列化详解示例

    序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据
    2014-02-02
  • C#/VB.NET实现PPT或PPTX转换为图像功能

    C#/VB.NET实现PPT或PPTX转换为图像功能

    由于大多数便携式设备支持浏览图片而不支持浏览PowerPoint 文件,所以相比较而言,图像对于用户而言更加友好。本文将利用C#/VB.NET实现PPT或PPTX转换为图像功能,需要的可以参考一下
    2022-08-08
  • 利用C#/VB.NET实现PPT转换为HTML

    利用C#/VB.NET实现PPT转换为HTML

    利用PowerPoint可以很方便的呈现多媒体信息,且信息形式多媒体化,表现力强。但难免在某些情况下我们会需要将PowerPoint转换为HTML格式,本文就为大家整理了转换方法,希望对大家有所帮助
    2023-05-05
  • C#利用StreamReader和StreamWriter类处理文本的字符编码使用示例

    C#利用StreamReader和StreamWriter类处理文本的字符编码使用示例

    .NET Framework 中,StreamReader 和 StreamWriter 类提供了一些方法来处理字符编码,这篇文章主要介绍了C#利用StreamReader和StreamWriter类处理文本的字符编码使用示例,需要的朋友可以参考下
    2024-06-06

最新评论