当我们定义一个泛型类时,如果传入的类型不确定为值类型或者为引用类型,那么为题就来了,如果给一个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;
}
//线程和锁以后讨论
开头讨论过的问题,如何给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: struct | T类型必须为值类型 |
where T: class | T类型必须为引用类型 |
where T: IFoo | T类型必须实现接口TFoo |
where T: Foo | T类型必须继承Foo基类 |
where T: new() | T类型必须具有默认的构造函数(自定义不行) |
where T2: T2 | T1类型继承泛型类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
因篇幅问题不能全部显示,请点此查看更多更全内容