当前位置: 移动技术网 > IT编程>开发语言>.net > 详解c# 泛型类的功能

详解c# 泛型类的功能

2020年10月30日  | 移动技术网IT编程  | 我要评论
在泛型类中,由于不知道泛型参数t是什么类型,可能是引用类型,也可能是值类型,因此不能将null等赋予泛型类型。如何对泛型对象赋初值、如何保证泛型的正确性等,以使用泛型文档管理器为例:  文档管理器用于

  在泛型类中,由于不知道泛型参数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# 泛型类的资料请关注移动技术网其它相关文章!

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网