• 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

  • 相关阅读:
    软件工程——理论、方法与实践 第十章
    软件工程——理论、方法与实践 第九章
    软件工程——理论、方法与实践 第八章
    软件工程——理论、方法与实践 第七章
    idea中运行ssm 或springboot项目时,project Structure的配置
    在springboot项目中引入quartz任务调度器。
    短链接的生成之工具类的编写--三种方式(亲测可用)
    IDEA中进行远程调试springboot项目
    linux服务器上部署springboot项目,并让他持续运行到后台
    使用maven 打包springboot项目步骤以及所遇到的问题
  • 原文地址:https://www.cnblogs.com/mq0036/p/10320580.html
Copyright © 2020-2023  润新知