C# 类型参数的约束
在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制。如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。这些限制称为约束。约束是使用 where 上下文关键字指定的。下表列出了六种类型的约束:
| 约束 | 说明 |
|---|---|
|
T:结构 |
类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。 |
|
T:类 |
类型参数必须是引用类型,包括任何类、接口、委托或数组类型。 |
|
T:new() |
类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。 |
|
T:<基类名> |
类型参数必须是指定的基类或派生自指定的基类。 |
|
T:<接口名称> |
类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。 |
|
T:U |
为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。 |
如果要检查泛型列表中的某个项以确定它是否有效,或者将它与其他某个项进行比较,则编译器必须在一定程度上保证它需要调用的运算符或方法将受到客户端代码可能指定的任何类型参数的支持。这种保证是通过对泛型类定义应用一个或多个约束获得的。例如,基类约束告诉编译器:仅此类型的对象或从此类型派生的对象才可用作类型参数。一旦编译器有了这个保证,它就能够允许在泛型类中调用该类型的方法。约束是使用上下文关键字 where 应用的。
public class Employee
{
private string name;
private int id; public Employee(string s, int i)
{
name = s;
id = i;
} public string Name
{
get { return name; }
set { name = value; }
} public int ID
{
get { return id; }
set { id = value; }
}
} public class GenericList<T> where T : Employee
{
private class Node
{
private Node next;
private T data; public Node(T t)
{
next = null;
data = t;
} public Node Next
{
get { return next; }
set { next = value; }
} public T Data
{
get { return data; }
set { data = value; }
}
} private Node head; public GenericList() //constructor
{
head = null;
} public void AddHead(T t)
{
Node n = new Node(t);
n.Next = head;
head = n;
} public IEnumerator<T> GetEnumerator()
{
Node current = head; while (current != null)
{
yield return current.Data;
current = current.Next;
}
} public T FindFirstOccurrence(string s)
{
Node current = head;
T t = null; while (current != null)
{
//The constraint enables access to the Name property.
if (current.Data.Name == s)
{
t = current.Data;
break;
}
else
{
current = current.Next;
}
}
return t;
}
}
约束使得泛型类能够使用 Employee.Name 属性,因为类型为 T 的所有项都保证是 Employee 对象或从 Employee 继承的对象。
可以对同一类型参数应用多个约束,并且约束自身可以是泛型类型,如下所示:
通过约束类型参数,可以增加约束类型及其继承层次结构中的所有类型所支持的允许操作和方法调用的数量。因此,在设计泛型类或方法时,如果要对泛型成员执行除简单赋值之外的任何操作或调用 System.Object 不支持的任何方法,您将需要对该类型参数应用约束。
在应用 where T : class 约束时,建议不要对类型参数使用 == 和 != 运算符,因为这些运算符仅测试引用同一性而不测试值相等性。即使在用作参数的类型中重载这些运算符也是如此。下面的代码说明了这一点;即使 String 类重载 == 运算符,输出也为 false。
public static void OpTest<T>(T s, T t) where T : class
{
System.Console.WriteLine(s == t);
}
static void Main()
{
string s1 = "foo";
System.Text.StringBuilder sb = new System.Text.StringBuilder("foo");
string s2 = sb.ToString();
OpTest<string>(s1, s2);
}
这种情况的原因在于,编译器在编译时仅知道 T 是引用类型,因此必须使用对所有引用类型都有效的默认运算符。如果需要测试值相等性,建议的方法是同时应用 where T : IComparable<T> 约束,并在将用于构造泛型类的任何类中实现该接口。
没有约束的类型参数(如公共类 SampleClass<T>{} 中的 T)称为未绑定的类型参数。未绑定的类型参数具有以下规则:
不能使用 != 和 == 运算符,因为无法保证具体类型参数能支持这些运算符。
可以在它们与 System.Object 之间来回转换,或将它们显式转换为任何接口类型。
可以将它们与 null 进行比较。将未绑定的参数与 null 进行比较时,如果类型参数为值类型,则该比较将始终返回 false。
用作约束的泛型类型参数称为裸类型约束。当具有自己的类型参数的成员函数需要将该参数约束为包含类型的类型参数时,裸类型约束很有用,如下面的示例所示:
在上面的示例中,T 在 Add 方法的上下文中是一个裸类型约束,而在 List 类的上下文中是一个未绑定的类型参数。
裸类型约束还可以在泛型类定义中使用。注意,还必须已经和其他任何类型参数一起在尖括号中声明了裸类型约束:
泛型类的裸类型约束的作用非常有限,因为编译器除了假设某个裸类型约束派生自 System.Object 以外,不会做其他任何假设。在希望强制两个类型参数之间的继承关系的情况下,可对泛型类使用裸类型约束。
原文来自:http://msdn.microsoft.com/zh-cn/library/d5x73970%28v=vs.80%29.aspx
C# 类型参数的约束的更多相关文章
- [转] C# 泛型类型参数的约束
啊.紫原文C# 泛型类型参数的约束 在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制.如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误.这些限制 ...
- 转载c#泛型 类型参数的约束(c#编程指南)
在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制.如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误.这些限制称为约束.约束是使用 where 上 ...
- C# 泛型类型参数的约束
在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制.如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误.这些限制称为约束.约束是使用 where 上 ...
- where 泛型类型参数及约束
private void InsertData<TRowMetadata, TFieldMetadata, TCellMetadata>(IMetadataReader<TRowMe ...
- C#的泛型的类型参数可以有带参数的构造函数的约束方式吗?
Review后看到标题让我十分羞愧自己语文功底太差,估计...请见谅......我还特地把这句写回开头了...... 问题 前天遇到的一个问题,所以在MSDN发了个问,刚也丰富了下问题,关于泛型的. ...
- C# 泛型约束
一.泛型简介1.1泛型通过使用泛型,可以创建这样的类.接口和方法,它们以一种类型安全的工作方式操作各种数据.本质上,术语“泛型”指的是“参数化类型”(parameterized types).参数化类 ...
- C#之使类型参数--泛型
1.泛型是什么 泛型的就是“通用类型”,它可以代替任何的数据类型,使类型参数化,从而达到只实现一个方法就可以操作多种数据类型的目的. 2.为什么使用泛型 举一个比较两个数大小的例子: 以上例子实现in ...
- .Net 泛型约束
本文内容 使用泛型约束的原因 未绑定的类型参数 作为约束的类型参数 参考资料 当"设计模式"出现时,人们提"用接口编程":后来,有了泛型,人们提"用泛 ...
- 编写高质量代码改善C#程序的157个建议——建议34:为泛型参数设定约束
建议34:为泛型参数设定约束 “约束”这个词可能会引起歧义,有些人肯能认为对泛型参数设定约束是限制参数的使用,实际情况正好相反.没有“约束”的泛型参数作用很有限,倒是“约束”让泛型参数具有了更多的行为 ...
随机推荐
- java资源下载之官网地址
[一].json下载地址 http://sourceforge.net/projects/json-lib/files/ [二].apache-commons下载地址 http://commons.a ...
- .NET MVC控制器向视图传递数据的四种方式
.NET MVC控制器向视图传递数据的四种方式: 1.ViewBag ViewBag.Mvc="mvc"; 2.ViewData ViewBag["Mvc"] ...
- WP8.1&Win10开发:TextBox获取和失去焦点小技巧
获取焦点:用Focus方法让Textbox获取焦点.代码示例:textbox.Focus(FocusState.Pointer); 失去焦点:让其他控件获取焦点,如Textblock控件(注意要将Te ...
- grootJs的vm结构
按看这段代码生成的vm groot.view("myview", function (vm, ve) { vm.say = "hello word!"; }) ...
- sql server T-SQL 基础
SQL语言按照用途可以分为如下3类: ①DDL(Data Definition Language) 数据定义语言: 定义修改和删除数据库.表.索引和视图等 ②DML(Data Manipulatio ...
- Android图像格式类及图像转换方法
Android图像格式类及图像转换方法介绍 一款软件的开发和图像密切相关,特别是移动应用程序,在视觉效果等方面是至关重要的,因为这直接关系到用户的体验效果.在Android程序开发的过程中,了解存在哪 ...
- jquery的基本动画方法
1 在使用$.extent()的时候,我们一般不放function类型,如果放的话,提前测试下. ?2 Function类型是一种基本类型还是引用类型呢. 3 $('<div>') 指创建 ...
- angular_$inject
<!DOCTYPE HTML> <html lang="zh-cn" ng-app="MainApp"> <head> &l ...
- rational rose USE CASE
- Webform之Repeater中的单选和多选的应用以及前段JS的实现
HTML中的代码 <asp:Repeater ID="Repeater1" runat="server"> <HeaderTemplate&g ...