(转)C# Where关键词的用法
where(泛型类型约束)
where关键词一个最重要的用法就是在泛型的声明、定义中做出约束。 
约束又分为接口约束、基类约束、构造函数约束、函数方法的约束,我们慢慢介绍。
接口约束
顾名思义,泛型参数必须实现相应的接口才可以,看一个例子:
public interface IAccount {
        string Name {
            get;
        }
        decimal Balance {
            get;
        }
}
 public class Account : IAccount {
        private string name;
        public string Name {
            get {
                return name;
            }
        }
        private decimal balance;
        public decimal Balance {
            get {
                return balance;
            }
        }
        public Account(string name = "", decimal balance = 0) {
            this.name = name;
            this.balance = balance;
        }
   }
   public class MyClass<T> where T : IAccount {
        public MyClass() {
            Console.WriteLine("In MyClass<T> Ctor");
        }
    }在public class MyClass<T> where T : IAccount中,where关键词指定了T必须实现IAcoount的接口才可以成功构造,例如:
namespace CSharp {
    class Program {
        static void Main(string[] args) {
            MyClass<Account> mc = new MyClass<Account>();
            //成功,Account实现了IAccount接口
            MyClass<string> m = new MyClass<string>();
            //构造失败,string没有实现IAccount接口,编译器提示错误
        }
    }
}T也可以是泛型接口,例如MSDN给出的例子:
public class MyGenericClass<T> where T:IComparable { }  
基类约束
类型参数必须是指定的基类或派生自指定的基类,多用于继承体系之下,看个例子:
public class Account : IAccount {
        private string name;
        public string Name {
            get {
                return name;
            }
        }
        private decimal balance;
        public decimal Balance {
            get {
                return balance;
            }
        }
        public Account(string name = "", decimal balance = 0) {
            this.name = name;
            this.balance = balance;
        }
    }
    public class AccountDrived : Account {
        public AccountDrived(string name = "", decimal balance = 0):base(name, balance) {
            Console.WriteLine("In AccountDrived Ctor");
        }
    }
   //泛型参数只能是Account或者Account的派生类
    public class MyClass2<T> where T : Account {
        public MyClass2() {
            Console.WriteLine("In MyClass2<T> Ctor");
        }
    }
    class Program {
        static void Main(string[] args) {
            MyClass2<Account> a = new MyClass2<Account>();
            MyClass2<AccountDrived> b = new MyClass2<AccountDrived>();
            //MyClass2<string> c = new MyClass2<string>(); - error
        }
    }构造函数约束
顾名思义,对类的构造函数进行了一定的约束,举个例子:
public class NoDefaultAccount : IAccount {
        private string name;
        public string Name {
            get {
                return name;
            }
        }
        private decimal balance;
        public decimal Balance {
            get {
                return balance;
            }
        }
        public NoDefaultAccount(string name) {
            this.name = name;
            this.balance = 0;
        }
    }
    public class Account : IAccount {
        private string name;
        public string Name {
            get {
                return name;
            }
        }
        private decimal balance;
        public decimal Balance {
            get {
                return balance;
            }
        }
        public Account(string name = "", decimal balance = 0) {
            this.name = name;
            this.balance = balance;
        }
    }
    public class AccountDrived : Account {}
    public class MyClass3<T> where T : class, new(){
        public MyClass3(){
            Console.WriteLine("In MyClass3<T> Ctor");
        }
    }
    class Program {
        static void Main(string[] args) {
            //1.MyClass3<Account> a = new MyClass3<Account>();
            MyClass3<AccountDrived> b = new MyClass3<AccountDrived>();//默认生成一个无参构造函数
            //2.MyClass3<NoDefaultAccount> c = new MyClass3<NoDefaultAccount>();//必须是有默认构造函数的非抽象类
        }
    }这里的重点是public class MyClass3<T> where T : class, new(),这表明参数T对应的类型必须是一个引用类型(class),new()表示具备无参构造函数。
NoDefaultAccount类内显然没有默认的构造函数,在Account中有public Account(string name = "", decimal balance = 0),给定了默认值,在AccountDerived中,由于我们没有显式的声明一个构造函数,于是C#会自动生成一个AccountDerived()。
令人疑惑的是,Account是有默认构造函数的,为何//1.MyClass3<Account> a = new MyClass3<Account>();这条语句编译器会报错呢? 
尝试后发现,C#和C++不一样,当你写下Account a = new Account();这条语句的时候,编译器会优先查找是否有public Account(),如果存在那么就构造对象,否则查找public Account(value = defaultvalue)这种带默认值的构造函数,两者是不一样的,并且是可以共存的。
class Account{
       //和C++不同,这并不是重定义
        public Account() {
            this.name = "xxxxx";
            this.balance = 10;
        }
        public Account(string name = "", decimal balance = 0) {
            this.name = name;
            this.balance = balance;
        }
 }new()这种约束特指是否存在 Account()这样的无参默认构造函数。
函数方法的约束
这种形式就比较简单了,上述三个约束不加在泛型类中,加在函数中即可,举个例子:
 public class Algorithm {
        public static decimal Total<TAccount>(IEnumerable<TAccount> e)
                              where TAccount : IAccount
        //这意味着调用Total函数传入的参数e必须是1.实现了IEnumerable接口的可迭代对象 2.e的可迭代元素必须是实现了IAcoount接口的
        {
            decimal total = 0;
            foreach(TAccount element in e) {
                total += element.Balance;
            }
            return total;
        }
        public static void Add<T>(T lhs, T rhs) where T : class, new() {
            //约束了T必须是引用类型,且必须定义了默认构造函数
            T ans = new T();
        }
    }
class Program {
        static void Main(string[] args) {
            List<Account> accounts = new List<Account>();
            accounts.Add(new Account("sixday", 100));
            accounts.Add(new Account("fiveday", 50));
            accounts.Add(new Account("sevenday", 70));
            Console.WriteLine("The answer is {0}", Algorithm.Total<Account>(accounts));
        }
    }泛型类型约束总结
最后,做一个小总结:
- where T : struct 这表明T必须是一个值类型,像是int,decimal这样的
- where T : class 这表明T必须是一个引用类型,像是自定义的类、接口、委托等
- where T : new() 这表明T必须有无参构造函数,且如果有多个where约束,new()放在最后面
- where T : [base class name] 这表明T必须是base class类获其派生类
- where T : [interface name] 这表明T必须实现了相应的接口
更多例子可以参考MSDN
where (查询表达式)
除了用于泛型约束之外,where还常用于查询表达式,可以直接参考MSDN的例子
文章转载自:https://blog.csdn.net/sixdaycoder/article/details/75356055
(转)C# Where关键词的用法的更多相关文章
- Where关键词的用法
		where(泛型类型约束) where关键词一个最重要的用法就是在泛型的声明.定义中做出约束. 约束又分为接口约束.基类约束.构造函数约束.函数方法的约束,我们慢慢介绍. 接口约束 顾名思义,泛型参数 ... 
- c++学习笔记2(const关键词的用法)
		定义常量指针 优势(便于类型检查,define无类型检查(目前不是很理解)) (函数参数为常量指针时,可避免函数内部不小心改变参数指针所指的地方,如有出现此类语句,编译则会报错) strcpy:复制字 ... 
- Linq的基本用用法
		Linq 的基本用法: Sort , OrderBy, Skip,Take,Where,Compare,Join,Distinct ,InsertRange 等关键词 Select用法 var sel ... 
- Hibernate学习-Hibernate查询语言HQL
		HQL(Hibernate Query Language)Hibernate查询语言,语法类似于SQL,可以直接使用实体类及属性. 使用HQL 可以避免使用JDBC 查询的一些弊端 不需要再编写繁复的 ... 
- 第九章  C语言在嵌入式中的应用
		上章回顾 编码的规范和程序版式 版权管理和申明 头文件结构和作用 程序命名 程序注释和代码布局规范 assert断言函数的应用 与0或NULL值的比较 内存的分配和释放细节,避免内存泄露 常量特性 g ... 
- var 和 dynamic在实际项目中的应用
		先回顾一下这两个关键词的用法. var是个语法糖,是在用var声明变量的那一刻就确定了其变量的类型. 因为需要在声明的时候就确定其类型,所以要求在用var声明隐式局部变量的时候必须初始化该变量. 编译 ... 
- 【阿里云产品公测】简单日志服务SLS使用评测 + 教程
		[阿里云产品公测]简单日志服务SLS使用评测 + 教程 评测介绍 被测产品: 简单日志服务SLS 评测环境: 阿里云基础ECS x2(1核, 512M, 1M) 操作系统: CentOS 6.5 x6 ... 
- Spring Data JPA教程, 第三部分: Custom Queries with Query Methods(翻译)
		在本人的Spring Data JPA教程的第二部分描述了如何用Spring Data JPA创建一个简单的CRUD应用,本博文将描述如何在Spring Data JPA中使用query方法创建自定义 ... 
- SLS评测报告
		什么是SLS? 简单日志服务(Simple Log Service,简称SLS)是针对日志收集.存储.查询和分析的服务.用户只需简单地配置日志产生的位置和格式等信息,就能实时查询海量日志,并可通过S ... 
随机推荐
- intel FPGA使用
			https://www.altera.com/documentation/swn1503506366945.html https://files.cnblogs.com/files/shaohef/o ... 
- 题说proxy
			昨天在和群友讨论时遇到一题是这样的. 题目描述 //Tomy非常敏感,不喜欢别人碰他的东西.一旦有人碰他就会大喊Don't Touch Me. //完成tomy这个对象,禁止对tomy的内容进行修改( ... 
- Codeforces 581F Zublicanes and Mumocrates - 树形动态规划
			It's election time in Berland. The favorites are of course parties of zublicanes and mumocrates. The ... 
- bzoj 3262 陌上花开 - CDQ分治 - 树状数组
			Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当 ... 
- uniGUI试用笔记(十一)
			最近研究了一下UniGUI的TuniDBGrid,记录一下免得忘记了. TuniDBGrid的重要属性包括: 1.列—TUniDBGridColumns和TUniDBGridColumn 每个列对象( ... 
- ng-model绑定的是ng-option中的什么?
			<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script sr ... 
- Hunter’s Apprentice 【判断多边形边界曲线顺逆时针】
			问题 H: Hunter's Apprentice 时间限制: 1 Sec 内存限制: 128 MB 提交: 353 解决: 39 [提交] [状态] [命题人:admin] 题目描述 When ... 
- 好用的js模板
			组织form下的 json对象 $.fn.serializeObject = function() { var o = {"unique_id":new Date().getTim ... 
- hihoCoder week15 最近公共祖先·二
			tarjan求lca 就是dfs序中用并查集维护下,当访问到询问的第二个点u的时候 lca就是第一点的find(fa[v]) fa[v] = u; // 当v为u的儿子 且 v已经dfs完毕 #i ... 
- (转) How a Kalman filter works, in pictures
			How a Kalman filter works, in pictures I have to tell you about the Kalman filter, because what it d ... 
