搜索
您的当前位置:首页正文

1.5.3 泛型类的特征

来源:好走旅游网

当我们定义一个泛型类时,如果传入的类型不确定为值类型或者为引用类型,那么为题就来了,如果给一个T类型的变量赋值?

值类型的不能位null,引用类型不能位0等等。如果泛型类型不需要对象类的特性,但需要调用泛型类中的某些特定方法,又该如何处理?

那么接下来,我们将讨论:

默认值

约束

继承

静态成员

本例从一个通用文档管理器开始,该文档管理器用于从队列读写文档和向队列读写文档。首先创建一个名为DocumentManager的新控制台项目并添加该类DocumentManager < T >。AddDocument方法向队列添加一个文档。如果队列不是空的,则只读属性IsDocumentAvailable返回true。

    public class DocumentManager<T>
    {
        private readonly Queue<T> _documentQueue = new Queue<T>();
        private readonly object _lockQueue = new object();
        public void AddDocument(T doc)
        {
            lock (_lockQueue)
            {
                _documentQueue.Enqueue(doc);
            }
        }
        public bool IsDocumentAvailable => _documentQueue.Count >0;
    }
//线程和锁以后讨论

默认值:default

开头讨论过的问题,如何给T类型的变量赋值,我们可以使用default关键字,

public T GetDocument()
{
T doc = default;
lock (_lockQueue)
{
doc = _documentQueue.Dequeue();
}
return doc;
}

default关键字会根据值类型和引用类型自动赋值为null或者0。

约束

首先看一段代码

    public interface IDocument
    {
        string Title { get; }
        string Content { get; }
    }
    
public class Document : IDocument
    {
        public Document(string title, string content)
        {
            Title = title;
            Content = content;
        }
        public string Title { get; }
        public string Content { get; }
    }
    
public void DisplayAllDocuments()
    {
        foreach (T doc in documentQueue)
        {
            Console.WriteLine(((IDocument)doc).Title);
        }
    }

第一个是接口,第二个是类,实现了第一个接口,第三个是方法。

这里面存在一个问题:在调用的时候使用了强制类型转换Console.WriteLine(((IDocument)doc).Title);

如果类型T 的doc没有实现接口,那么在转换的过程中会报错,那么我们就需要加一个约束,并描述清楚。

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

首先要将T类型该我TDocument类型,这样具有描述性,前面的命名规则我们也提到过,后面需要加上where 进行约束。确保该类型是继承IDocument的。

需要注意的是T和TDocument在编译执行的时候没有任何区别,这样只是为了增加可读性。

同时在调用的时候也不用进行强制类型转换了

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

泛型类的约束有很多,具体如下表

泛型约束总结
泛型约束描述
where T:  structT类型必须为值类型
where T:  classT类型必须为引用类型
where T:  IFooT类型必须实现接口TFoo
where T:  FooT类型必须继承Foo基类
where T:  new()T类型必须具有默认的构造函数(自定义不行)
where T2:  T2T1类型继承泛型类T2

泛型类的约束,不仅限于一个约束,是可以进行组合的where T: IFoo, new(),T类型必须实现IFoo接口,必须具有默认构造函数。

继承

前面我们看到了,泛型类是可以继承泛型接口的,同样的,泛型类可以派生泛型类

     public class Base<T>
    { }
    public class Derived<T> : Base<T>
    { }

并且还泛型类可以派生非泛型类。 

    public class Base<T>
    { }
    public class Derived : Base<T>
    { }

根据泛型类可以派生非泛型类,我们便可以声明一个抽象泛型类,然后派生特定的类,已实现特定的功能。

    public abstract class Calc<T>
    {
        public abstract T Add(T x, T y);
        public abstract T Sub(T x, T y);
    }
    public class IntCalc : Calc<int>
    {
        public override int Add(int x, int y) => x + y;
        public override int Sub(int x, int y) => x - y;
    }

我们还可以对多个参数的泛型类,继承它并只实现其中的一部分(两个泛型参数的基类)

public class Query<TRequest, TResult>
{}
public StringQuery<TRequest> : Query<TRequest, string>
{}

静态字段

泛型类是可以实现静态字段的,并且只能在一个实例中使用,不能夸实例使用。

public class StaticDemo<T>
{
public static int x;
}

举个例子:我们为string类型的实例赋值为4,在对int类型的赋值为5,结果最后stirng类型的仍然是4,他们之间是不互通的。

StaticDemo<string>.x = 4;
StaticDemo<int>.x = 5;
Console.WriteLine(StaticDemo<string>.x); // writes 4

 

因篇幅问题不能全部显示,请点此查看更多更全内容

Top