C# 泛型类型参数的约束

http://www.cnblogs.com/rinack/p/5676311.html
在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制。如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。这些限制称为约束。约束是使用 where 上下文关键字指定的。下表列出了六种类型的约束:

where T: struct
类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。有关更多信息,请参见使用可以为 null 的类型(C# 编程指南)。
where T : class
类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。
where T:new()
类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。
where T:<基类名>
类型参数必须是指定的基类或派生自指定的基类。
where T:<接口名称>
类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
where 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 继承的对象。
可以对同一类型参数应用多个约束,并且约束自身可以是泛型类型,如下所示:

class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
{
    // ...
}
 
通过约束类型参数,可以增加约束类型及其继承层次结构中的所有类型所支持的允许操作和方法调用的数量。因此,在设计泛型类或方法时,如果要对泛型成员执行除简单赋值之外的任何操作或调用 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 = "target";System.Text.StringBuilder sb = new System.Text.StringBuilder("target");string s2 = sb.ToString();OpTest<string>(s1, s2);
}

这种情况的原因在于,编译器在编译时仅知道 T 是引用类型,因此必须使用对所有引用类型都有效的默认运算符。如果必须测试值相等性,建议的方法是同时应用 where T : IComparable<T> 约束,并在将用于构造泛型类的任何类中实现该接口。

约束多个参数

可以对多个参数应用约束,并对一个参数应用多个约束,如下面的示例所示:

class Base { }
class Test<T, U>
    where U : struct

where T : Base, new() { }

未绑定的类型参数

没有约束的类型参数(如公共类 SampleClass<T>{} 中的 T)称为未绑定的类型参数。未绑定的类型参数具有以下规则:

不能使用 != 和 == 运算符,因为无法保证具体类型参数能支持这些运算符。

可以在它们与 System.Object 之间来回转换,或将它们显式转换为任何接口类型。

可以将它们与 null 进行比较。将未绑定的参数与 null 进行比较时,如果类型参数为值类型,则该比较将始终返回 false。

作为约束的类型参数

将泛型类型参数作为约束使用,在具有自己类型参数的成员函数必须将该参数约束为包含类型的类型参数时非常有用,如下示例所示:

class List<T>
{
    void Add<U>(List<U> items) where U : T {/*...*/}

}

在上面的示例中,T 在 Add 方法的上下文中是一个类型约束,而在 List 类的上下文中是一个未绑定的类型参数。

类型参数还可在泛型类定义中用作约束。请注意,必须在尖括号中声明此类型参数与任何其他类型的参数:

//Type parameter V is used as a type constraint.
public class SampleClass<T, U, V> where T : V { }
泛型类的类型参数约束的作用非常有限,因为编译器除了假设类型参数派生自 System.Object 以外,不会做其他任何假设。在希望强制两个类型参数之间的继承关系的情况下,可对泛型类使用参数类型约束。
========

泛型类型参数及约束

http://www.cnblogs.com/wanghonghu/archive/2012/07/11/2586920.html
泛型类型参数简介
    在定义泛型类型和泛型方法时,常用到泛型类型参数,泛型类型参数是在实例化泛型时指定类型的占位符。泛型类型参数放在“<>”内。

泛型类型参数命名建议:

(1)当泛型类型参数为单个字母时,建议用T表示。

(1)当泛型类型参数用单词定义时,建议在单词前加T。

private void PromptName<T>(T t) {}
private void PromptName<Tuser>(Tuser user){}
泛型类型参数约束
      在定义泛型类时,可以对在实例化泛型类时用于类型参数的类型种类施加限制。如果实例化泛型类时使用某个约束所不允许的类型来实例化类,则会产生编译时错误。

泛型约束分类:

约束

说明

T:结构

类型参数必须是值类型。 可以指定除 Nullable 以外的任何值类型。

T:类

类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。

T:new()

类型参数必须具有无参数的公共构造函数。 当与其他约束一起使用时,new() 约束必须最后指定。

T:<基类名>

类型参数必须是指定的基类或派生自指定的基类。

T:<接口名称>

类型参数必须是指定的接口或实现指定的接口。 可以指定多个接口约束。 约束接口也可以是泛型的。

T:U

为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。

(1)类型参数约束为结构(struct)。

    public class ShowObjectType<T> where T : struct{public void ShowValue<T>(T t){Console.WriteLine(t.GetType());}}class GenericConstraint{static void Main(){          ShowObjectType<int> showInt = new ShowObjectType<int>();showInt.ShowValue<int>(5);showInt.ShowValue(5);//从参数可以推导出类型参数类型,则可以省略类型参数类型//因为约束为值类型,下面代码不能通过编译ShowObjectType<string> showString = new ShowObjectType<string>();showString.ShowValue("5");Console.Read();}}

(2)类型参数约束为类(class)。

在应用 where T : class 约束时,避免对类型参数使用 == 和 != 运算符,因为这些运算符仅测试类型为引用类型,而不测试值相等性。

    class GenericConstraint{static void Main(){List<string > list = new List<string>();AddClass<string>(list, "hello generic");Console.Read();}private static void AddClass<T>(List<T> list, T t) where T : class{list.Add(t);}}

(4)类型参数约束为具体类。

约束为具体类时,可利用类型参数调用具体类的属性和方法。

class GenericConstraint
    {
        static void Main()
        {
            Person person = new Person { ID = 1, Name = "David" };
            PromptName<Person>(person);

Console.Read();
        }

//此约束T为Person对象或者继承Person对象
        private static void PromptName<T>(T t) where T : Person 
        {
            //此处可使用Person的Name属性
            if (t.Name == "David")
            {
                Console.WriteLine("Person name is David");
            }

string name = t.GetName();
            Console.WriteLine("Person name is {0}", name);
        }
    }
    public class Person
    {
        private int id;
        public int ID
        {
            get { return id; }
            set { id = value; }
        }

private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        public string GetName()
        {
            return Name;
        }
    }
复制代码
    (5)约束多个参数。

class Base { }
class Test<T, U>
    where U : struct
    where T : Base, new() { }
    (6)未绑定类型参数。

没有约束的类型参数,称为未绑定的类型参数。

class  List<T>{}
========

泛型类型参数约束 <T> where T : class,new(){}

.NET支持的类型参数约束有以下五种:
where T : struct                               | T必须是一个结构类型
where T : class                               | T必须是一个类(class)类型,不能是结构(structure)类型   引用类型
where T : new()                               | T必须要有一个无参构造函数    可以被new()
where T : NameOfBaseClass          | T必须继承名为NameOfBaseClass的类
where T : NameOfInterface             | T必须实现名为NameOfInterface的接口
========

where(泛型类型约束)

http://www.cnblogs.com/lystory/p/5104865.html
定义:在定义泛型的时候,我们可以使用 where 限制参数的范围。

使用:在使用泛型的时候,你必须尊守 where 限制参数的范围,否则编译不会通过。

六种类型的约束:

T:类(类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。)

class MyClass<T, U>
        where T : class///约束T参数必须为“引用 类型{ }”
        where U : struct///约束U参数必须为“值 类型”
    { }
T:结构(类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。)

class MyClass<T, U>
        where T : class///约束T参数必须为“引用 类型{ }”
        where U : struct///约束U参数必须为“值 类型”
    { }
T:new()(类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。)

class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
{
    // ...
}
T:<基类名>(类型参数必须是指定的基类或派生自指定的基类。)

public class Employee{}

public class GenericList<T> where T : Employee
T:<接口名称>(类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。)

复制代码
    /// <summary>
    /// 接口
    /// </summary>
    interface IMyInterface
    {
    }

/// <summary>
    /// 定义的一个字典类型
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TVal"></typeparam>
    class Dictionary<TKey, TVal>
        where TKey : IComparable, IEnumerable
        where TVal : IMyInterface
    {
        public void Add(TKey key, TVal val)
        {
        }
    }
复制代码
T:U(为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。也就是说T和U的参数必须一样)

class List<T>
{
    void Add<U>(List<U> items) where U : T {/*...*/}
}

一、可用于类:

public class MyGenericClass<T> where T:IComparable { }
二、可用于方法:

public bool MyMethod<T>(T t) where T : IMyInterface { }
三、可用于委托:

delegate T MyDelegate<T>() where T : new()

在实际项目中什么时候用到它们?

有时候你在做一个项目的时候,你需要用到泛型,你只希望传给你的泛型参数是限定范围的,

比如你希望值类型,或者是引用类型,或者是继承至某个类型、或者是符合某个接扣的类型,

这个时候你该如何办?你就需要用到 WHERE 来限定了。

参考文档:

https://msdn.microsoft.com/zh-cn/library/d5x73970.aspx

https://msdn.microsoft.com/zh-cn/library/bb384067.aspx
========

c# 泛型类型参数与约束的深入分析

http://www.jb51.net/article/37657.htm
本篇文章是对c#中泛型类型参数与约束进行了详细的分析介绍,需要的朋友参考下
..泛型类型参数简介
在定义泛型类型和泛型方法时,常用到泛型类型参数,泛型类型参数是在实例化泛型时指定类型的占位符。泛型类型参数放在“<>”内。
泛型类型参数命名建议:
(1)当泛型类型参数为单个字母时,建议用T表示。
(2)当泛型类型参数用单词定义时,建议在单词前加T。

复制代码 代码如下:
private void PromptName<T>(T t) {}
private void PromptName<Tuser>(Tuser user){}

泛型类型参数约束
在定义泛型类时,可以对在实例化泛型类时用于类型参数的类型种类施加限制。如果实例化泛型类时使用某个约束所不允许的类型来实例化类,则会产生编译时错误。
泛型约束分类:

约束
 说明
 
T:结构
 类型参数必须是值类型。 可以指定除 Nullable 以外的任何值类型。 
 
T:类
 类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。
 
T:new()
 类型参数必须具有无参数的公共构造函数。 当与其他约束一起使用时,new() 约束必须最后指定。
 
T:<基类名>
 类型参数必须是指定的基类或派生自指定的基类。
 
T:<接口名称>
 类型参数必须是指定的接口或实现指定的接口。 可以指定多个接口约束。 约束接口也可以是泛型的。
 
T:U
 为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。

(1)类型参数约束为结构(struct)。

复制代码 代码如下:
public class ShowObjectType<T> where T : struct
    {
        public void ShowValue<T>(T t)
        {
            Console.WriteLine(t.GetType());
        }
    }
    class GenericConstraint
    {
        static void Main()
        {

ShowObjectType<int> showInt = new ShowObjectType<int>();
            showInt.ShowValue<int>(5);
            showInt.ShowValue(5);//从参数可以推导出类型参数类型,则可以省略类型参数类型

//因为约束为值类型,下面代码不能通过编译
            ShowObjectType<string> showString = new ShowObjectType<string>();
            showString.ShowValue("5");
            Console.Read();
        }
    }

(2)类型参数约束为类(class)。
在应用 where T : class 约束时,避免对类型参数使用 == 和 != 运算符,因为这些运算符仅测试类型为引用类型,而不测试值相等性。

复制代码 代码如下:
class GenericConstraint
    {
        static void Main()
        {
              List<string > list = new List<string>();
            AddClass<string>(list, "hello generic");
            Console.Read();
        }
        private static void AddClass<T>(List<T> list, T t) where T : class
        {
            list.Add(t);
        }
    }

(3)类型参数约束为具体类。
约束为具体类时,可利用类型参数调用具体类的属性和方法。

复制代码 代码如下:
class GenericConstraint
    {
        static void Main()
        {
            Person person = new Person { ID = 1, Name = "David" };
            PromptName<Person>(person);
            Console.Read();
        }
        //此约束T为Person对象或者继承Person对象
        private static void PromptName<T>(T t) where T : Person 
        {
            //此处可使用Person的Name属性
            if (t.Name == "David")
            {
                Console.WriteLine("Person name is David");
            }
            string name = t.GetName();
            Console.WriteLine("Person name is {0}", name);
        }
    }
    public class Person
    {
        private int id;
        public int ID
        {
            get { return id; }
            set { id = value; }
        }
        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        public string GetName()
        {
            return Name;
        }
    }

(4)约束多个参数。

复制代码 代码如下:
class Base { }
class Test<T, U>
    where U : struct
    where T : Base, new() { }

(5)未绑定类型参数。
 没有约束的类型参数,称为未绑定的类型参数。

复制代码 代码如下:
class  List<T>{}

========

C# 泛型类型参数的约束相关推荐

  1. 类型参数的约束(C# 编程指南)

    类型参数的约束(C# 编程指南) Visual Studio 2005 其他版本 38(共 55)对本文的评价是有帮助 - 评价此主题 在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类 ...

  2. C# 类型参数的约束

    在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制.如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误.这些限制称为约束.约束是使用 where 上 ...

  3. Java泛型进阶 - 如何取出泛型类型参数

    在JDK5引入了泛型特性之后,她迅速地成为Java编程中不可或缺的元素.然而,就跟泛型乍一看似乎非常容易一样,许多开发者也非常容易就迷失在这项特性里. 多数Java开发者都会注意到Java编译器的类型 ...

  4. java实现泛型检索_高级Java泛型:检索泛型类型参数

    java实现泛型检索 在JDK5中引入Java泛型之后, Java泛型Swift成为许多Java程序的组成部分. 但是,乍一看似乎很简单的Java泛型,程序员很快就会迷失此功能. 大多数Java程序员 ...

  5. 高级Java泛型:检索泛型类型参数

    在JDK5中引入Java泛型之后, Java泛型Swift成为许多Java程序的组成部分. 但是,乍一看似乎很简单的Java泛型,程序员很快就会迷失此功能. 大多数Java程序员都知道Java编译器的 ...

  6. java 编译参数_java – 为什么要编译?代码似乎打破了类型参数的约束

    在下面的测试中,TesterClass对其两个类型参数之间的关系设置了约束.方法func2()似乎打破了这个约束,我希望它会在某处导致类型编译错误(在func2的定义中,或者每当类与String之外的 ...

  7. 学员优秀博文赏析:泛型通配符及约束

    最课程师徒班的同学正在红红火火的学习中.仿佛.应该.必须,到了跟大家阶段性汇报成果的时候了.为什么,因为毕竟当时把师徒班说的那么好,就业班的同学该要闹革命了. 师徒班相较于就业班,虽然课程内容和总量完 ...

  8. java泛型和类型通配符,java – 泛型,类型参数和通配符

    通用类型要了解的主要内容是它们不是协变的. 所以你可以这样做: final String string = "string"; final Object object = stri ...

  9. 类型参数作为约束 where T : U 的作用

    public class ClassA { } public class ClassB : ClassA { } public class TTSS<T> { public void Ad ...

最新文章

  1. vue vuex 挂载_Vue $mount()手动挂载
  2. 发布开源库的踩坑经历:jitpack.io
  3. CryptoAPI与openssl RSA非对称加密解密(PKCS1 PADDING)交互
  4. leetcode 436. Find Right Interval | 436. 寻找右区间(二分查找不小于某值的第一个位置)
  5. 大型网站后台架构的演变
  6. linux系统如何启用ftp服务
  7. 二 面向对象三大特性
  8. 项目学生:带有Jersey的Web服务服务器
  9. java 布尔逻辑运算符_Java运算符
  10. java 运行 出现选择_Eclipse 运行出现java.lang.NoClassDefFoundError的解决方法
  11. magento paypal付款实现前台切换货币付款
  12. 简单的二维数组问题,不用不知道,一用吓一跳
  13. 电脑怎么打出冒号符号_标点符号的用法,资深老师带你学习,提高学生学习效率...
  14. Python3 从零单排17_类的继承
  15. 解决unable to find a qt build,to solve this problem specify a qt build
  16. 嵌入式linux开发实战——项目1认识嵌入式系统
  17. 5.1.2全景声音箱摆位_杜比全景声7.1.2和7.1.4音箱摆位有什么区别
  18. 3.接口测试用例书写
  19. 无偿加班竟然被开除,程序员坐不住了
  20. PeopleSoft 快捷键

热门文章

  1. 通过GPG非对称加密工具验证ECharts发布版本实例演示,win10下Gnu Privacy Guard工具的安装和使用方法
  2. C++ leetcode 5. 最长回文子串 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
  3. CTFshow 命令执行 web61
  4. 多彩投网站动态爬取[python+selenium]
  5. 【Kaggle-MNIST之路】CNN+改进过的损失函数(三)
  6. 配置远程服务器jupyter
  7. jmeter http并发测试时报错
  8. 5-1 Django的路由层(urlconf)
  9. 新建一个Windows Service的方法
  10. tomcat+mysql数据库连接池的操作