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

 
约束 说明

T:结构

类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。有关更多信息,请参见使用可空类型(C# 编程指南)。

T:类

类型参数必须是引用类型,包括任何类、接口、委托或数组类型。

T:new()

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

T:<基类名>

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

T:<接口名称>

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

T:U

为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。

 使用约束的原因

如果要检查泛型列表中的某个项以确定它是否有效,或者将它与其他某个项进行比较,则编译器必须在一定程度上保证它需要调用的运算符或方法将受到客户端代码可能指定的任何类型参数的支持。这种保证是通过对泛型类定义应用一个或多个约束获得的。例如,基类约束告诉编译器:仅此类型的对象或从此类型派生的对象才可用作类型参数。一旦编译器有了这个保证,它就能够允许在泛型类中调用该类型的方法。约束是使用上下文关键字 where 应用的。

[转]

泛型约束基本上有五种:

  • 值类型约束:要求泛型参数必须是值类型,例如int,short以及自定义的stuct等

public class MyClass2<T> 
        where T : struct//这个泛型类只接受值类型的泛型参数 
    { 
    }

  • 引用类型约束:要求泛型参数必须是引用类型,例如string,object,以及自定义的class

public class MyClass<T> 
        where T:class//这个泛型类只接受引用类型的泛型参数 
    { 
    }

  • 构造函数约束:要求泛型参数必须有构造函数

public class MyClass3<T> 
        where T : new() 
    { 
    }

  • 接口约束:要求泛型参数必须实现某个接口

public class MyClass4<T> 
        where T : System.IComparable 
    { 
    }

  • 基类约束:要求泛型参数必须继承某个基类

public class MyClass5<T> 
        where T : Customer 
    { 
    }

实战代码:

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Common;
using Dare.Utilities.Data;
using Dare.DN.Components;
using System.Data;
using log4net.Core;

namespace Dare.DN.Data
{
    public abstract class DataProviderTemplate<Entity, Key> : DataProviderBase
        where Entity : class, IEntity, IEntity<Key>,new()
        where Key : struct

    {
       
        protected List<EntityRelationDataProvider<Entity, Key>> relationDataProviders;

public DataProviderTemplate()
        {
            relationDataProviders = new List<EntityRelationDataProvider<Entity, Key>>();
        }

#region 关系操作方法
        public void AddRelationDataProviders(params EntityRelationDataProvider<Entity, Key>[] providers)
        {
            relationDataProviders.AddRange(providers);
        }

protected virtual void InsertRelations(TransactionManager manager, DbCommand cmd, IEnumerable<Entity> entities)
        {
            if (entities == null) return;
            foreach (EntityRelationDataProvider<Entity, Key> provider in relationDataProviders)
            {
                provider.Insert(manager, cmd, entities);
            }
        }

protected virtual void InsertRelations(TransactionManager manager, DbCommand cmd, params Entity[] entities)
        {
            InsertRelations(manager, cmd, (IEnumerable<Entity>)entities);
        }

protected virtual void UpdateRelations(TransactionManager manager, DbCommand cmd, IEnumerable<Entity> entities)
        {
            if (entities == null) return;
            foreach (EntityRelationDataProvider<Entity, Key> provider in relationDataProviders)
            {
                provider.Update(manager, cmd, entities);
            }
        }

protected virtual void UpdateRelations(TransactionManager manager, DbCommand cmd, params Entity[] entities)
        {
            UpdateRelations(manager, cmd, (IEnumerable<Entity>)entities);
        }

protected virtual void DeleteRelations(TransactionManager manager, DbCommand cmd, IEnumerable<Key> keys)
        {
            if (keys == null) return;
            foreach (EntityRelationDataProvider<Entity, Key> provider in relationDataProviders)
            {
                provider.Delete(manager, cmd, keys);
            }
        }

protected virtual void DeleteRelations(TransactionManager manager, DbCommand cmd, params Key[] keys)
        {
            DeleteRelations(manager, cmd, (IEnumerable<Key>)keys);
        }

protected virtual void DeleteRelations(TransactionManager manager, DbCommand cmd, string whereClause)
        {
            string whereCluase = ProcessWhereClause(whereClause);
            foreach (EntityRelationDataProvider<Entity, Key> provider in relationDataProviders)
            {
                provider.Delete(manager, cmd, whereClause);
            }
        }

protected virtual void CleanRelations(DbCommand cmd)
        {
            foreach (EntityRelationDataProvider<Entity, Key> provider in relationDataProviders)
            {
                provider.Clean(cmd);
            }
        }

protected virtual void RetrieveRelations(TransactionManager manager, DbCommand cmd, IEnumerable<Entity> entities)
        {
            if (entities == null) return;
            foreach (EntityRelationDataProvider<Entity, Key> provider in relationDataProviders)
            {
                provider.Retrieve(manager, cmd, entities);
            }
        }

protected virtual void RetrieveRelations(TransactionManager manager, DbCommand cmd, params Entity[] entities)
        {
            RetrieveRelations(manager, cmd, (IEnumerable<Entity>)entities);
        }
        #endregion

#region 基本操作方法
        public abstract void Insert(TransactionManager manager, Entity entity);

public abstract void Import(TransactionManager manager, IEnumerable<Entity> entities);

public abstract void Update(TransactionManager manager, Entity entity);

public abstract void Delete(TransactionManager manager, Key key);

public abstract void DeleteAll(TransactionManager manager, string whereClause);

public abstract Entity Get(TransactionManager manager, Key key);

public virtual List<Entity> GetAll(TransactionManager manager, string whereClause, string orderBy)
        {
            return GetPaged(manager, whereClause, orderBy, -1, -1);
        }

public abstract List<Entity> GetPaged(TransactionManager manager, string whereClause, string orderBy, int pageIndex, int pageSize);

public abstract int GetCount(TransactionManager manager, string whereClause);

public abstract long GetVersion(TransactionManager manager, string whereClause);

public abstract Entity Fill(IDataReader reader, Entity entity);
        #endregion

#region 内部操作模板方法
        protected virtual int InternalExecuteNonQuery(TransactionManager manager, string sql, params DbParameter[] parameters)
        {
            int result = 0;
            Execute(manager, delegate(TransactionManager mgr, DbCommand cmd)
            {
                /*------------------------------数据库SQL操作开始----------------------------------*/
                //获取SQL语句
                cmd.CommandText = sql;
                cmd.Parameters.AddRange(parameters);

//执行
                result = cmd.ExecuteNonQuery();
               
                /*------------------------------数据库SQL操作结束----------------------------------*/
            });

return result;
        }

protected virtual List<Entity> InternalGetList(TransactionManager manager, string sql, params DbParameter[] parameters)
        {
            List<Entity> list = new List<Entity>();
            Execute(manager, delegate(TransactionManager mgr, DbCommand cmd)
            {
                /*------------------------------数据库SQL操作开始----------------------------------*/
                //获取SQL语句
                cmd.CommandText = sql;
                cmd.Parameters.AddRange(parameters);

//执行获取实体集
                using (IDataReader reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        list.Add(Fill(reader, null));
                    }
                }

//获取关系对象
                RetrieveRelations(mgr, cmd, list);

/*------------------------------数据库SQL操作结束----------------------------------*/
            });

return list;
        }

protected virtual List<Key> InternalGetKeyList(TransactionManager manager, string sql, params DbParameter[] parameters)
        {
            List<Key> list = new List<Key>();
            Execute(manager, delegate(TransactionManager mgr, DbCommand cmd)
            {
                /*------------------------------数据库SQL操作开始----------------------------------*/
                //获取SQL语句
                cmd.CommandText = sql;
                cmd.Parameters.AddRange(parameters);

//执行获取实体集
                using (IDataReader reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        list.Add((Key)Convert.ChangeType(reader.GetValue(0), typeof(Key)));
                    }
                }

/*------------------------------数据库SQL操作结束----------------------------------*/
            });

return list;
        }

protected virtual T InternalGetValue<T>(TransactionManager manager, string sql, T defaultValue, params DbParameter[] parameters)
        {
            T val = default(T);
            Execute(manager, delegate(TransactionManager mgr, DbCommand cmd)
            {
                /*------------------------------数据库SQL操作开始----------------------------------*/
                //获取SQL语句
                cmd.CommandText = sql;
                cmd.Parameters.AddRange(parameters);

//执行获取实体集
                object objValue = cmd.ExecuteScalar();
                val = DbConvert.ChangeType<T>(objValue, defaultValue);

/*------------------------------数据库SQL操作结束----------------------------------*/
            });

return val;
        }

protected virtual List<T> InternalGetValueList<T>(TransactionManager manager, string sql, T defaultValue, params DbParameter[] parameters)
        {
            List<T> list = new List<T>();
            Execute(manager, delegate(TransactionManager mgr, DbCommand cmd)
            {
                /*------------------------------数据库SQL操作开始----------------------------------*/
                //获取SQL语句
                cmd.CommandText = sql;
                cmd.Parameters.AddRange(parameters);

//执行获取实体集
                using (IDataReader reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        list.Add(DbConvert.ChangeType<T>(reader[0], defaultValue));
                    }
                }

/*------------------------------数据库SQL操作结束----------------------------------*/
            });

return list;
        }

public delegate T FillEntityHandler<T>(IDataReader reader, T entity);
        public delegate void AfterRetrievedEntityListHandler<T>(TransactionManager mgr, DbCommand cmd, IEnumerable<T> entities);

protected T InternalGet<T>(TransactionManager manager, string sqlGet, FillEntityHandler<T> fillEntityHandler, AfterRetrievedEntityListHandler<T> afterRetrieveHandler, params DbParameter[] parameters)
            where T : class
        {
            if (fillEntityHandler == null) throw new ArgumentNullException("fillEntityHandler", "实体数据填充调用方法不能为空!");
            T entity = null;
            Execute(manager, delegate(TransactionManager mgr, DbCommand cmd)
            {
                /*------------------------------数据库SQL操作开始----------------------------------*/
                //获取SQL语句
                cmd.CommandText = sqlGet;
                cmd.Parameters.AddRange(parameters);

//执行获取实体
                using (IDataReader reader = cmd.ExecuteReader())
                {
                    if (reader.Read())
                    {
                        entity = fillEntityHandler(reader, null);
                    }
                }

if (afterRetrieveHandler != null && entity != null)
                {
                    afterRetrieveHandler(mgr, cmd, new T[] { entity });
                }
                /*------------------------------数据库SQL操作结束----------------------------------*/
            });

return entity;
        }

protected Entity InternalGet(TransactionManager manager, string sqlGet, params DbParameter[] parameters)
        {
            return InternalGet<Entity>(manager, sqlGet, Fill, RetrieveRelations, parameters);
        }

protected List<Entity> InternalGetPaged(TransactionManager manager, string sqlGetPaged, string sqlGetCount, int pageIndex, int pageSize, out int totalCount, params DbParameter[] parameters)
        {
            return InternalGetPaged<Entity>(manager, sqlGetPaged, sqlGetCount, Fill, RetrieveRelations, pageIndex, pageSize, out totalCount, parameters);
        }

protected List<T> InternalGetPaged<T>(TransactionManager manager, string sqlGetPaged, string sqlGetCount, FillEntityHandler<T> fillEntityHandler, AfterRetrievedEntityListHandler<T> afterRetrieveHandler, int pageIndex, int pageSize, out int totalCount, params DbParameter[] parameters)
            where T:class
        {
            if (fillEntityHandler == null) throw new ArgumentNullException("fillEntityHandler", "实体数据填充调用方法不能为空!");
            List<T> list = null;
            int count = 0;
            Execute(manager, delegate(TransactionManager mgr, DbCommand cmd)
            {
                /*------------------------------数据库SQL操作开始----------------------------------*/
                //获取总记录数
                cmd.CommandText = sqlGetCount;
                cmd.Parameters.AddRange(parameters);
                count = Convert.ToInt32(cmd.ExecuteScalar());

if (count > 0)
                {
                    //确定分页和获取记录的数量
                    if (pageIndex < 0 || pageSize <= 0)
                    {
                        list = new List<T>(count); //不用分页
                    }
                    else if (count > (pageIndex-1) * pageSize)
                    {
                        list = new List<T>(pageSize);  //使用分页
                    }
                    else
                    {
                        list = new List<T>(0); //分页超过记录数量,输出空记录集
                        return;
                    }

//获取记录集
                    cmd.CommandText = sqlGetPaged;
                    using (IDataReader reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            list.Add(fillEntityHandler(reader, null));
                        }
                    }

if (afterRetrieveHandler != null)
                    {
                        afterRetrieveHandler(mgr, cmd, list);
                    }
                }
                else
                {
                    list = new List<T>(0); //无记录返回空记录集
                    return;
                }
                /*------------------------------数据库SQL操作结束----------------------------------*/
            });

totalCount = count;
            return list;
        }
        #endregion
    }
}

相关资料:

c# 泛型<T>类型参数T的约束where的更多相关文章

  1. C#的泛型的类型参数可以有带参数的构造函数的约束方式吗?

    Review后看到标题让我十分羞愧自己语文功底太差,估计...请见谅......我还特地把这句写回开头了...... 问题 前天遇到的一个问题,所以在MSDN发了个问,刚也丰富了下问题,关于泛型的. ...

  2. 已经为类型参数“Chart”指定了 constraint 子句。必须在单个 where 子句中指定类型参数的所有约束

    public abstract class FillWorkBook<TModel, Chart> where TModel : struct where Chart : new() wh ...

  3. C#泛型对类型参数的推断

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  4. C# 语法特性 - 泛型(C#2.0)

    泛型将 类型参数 的概念引入了 .NET Framework. 泛型主要有两个优点: 1.编译时可以保证类型安全. 2.不用做类型转换,获得一定的性能提升. 泛型方法.泛型委托.泛型接口 除了泛型类之 ...

  5. ASP.NET MVC 企业级实战

    1.泛型 public class List<T>{ } 当定义泛型类的实例时,必须指定这个实例所存储的实际类型,泛型允许程序员将一个实际的数据类型规约延迟至泛型的实例被创建时才确定,泛型 ...

  6. (转).net面试题(老赵)

    转自:http://www.cnblogs.com/chenxiaoran/archive/2012/05/27/2519988.html 1.什么是CLR 公共语言运行时(Comman langua ...

  7. C# 各版本新特性

    C# 2.0 泛型(Generics) 泛型是CLR 2.0中引入的最重要的新特性,使得可以在类.方法中对使用的类型进行参数化. 例如,这里定义了一个泛型类: class MyCollection&l ...

  8. C# 语言历史版本特性(C# 1.0到C# 7.1汇总更新) C#各版本新特性 C#版本和.NET版本以及VS版本的对应关系

    C# 语言历史版本特性(C# 1.0到C# 7.1汇总更新) 2017年08月06日 11:53:13 阅读数:6705 历史版本 C#作为微软2000年以后.NET平台开发的当家语言,发展至今具有1 ...

  9. C# 2.0新加特性

    泛型(Generics) 泛型是CLR 2.0中引入的最重要的新特性,使得可以在类.方法中对使用的类型进行参数化. 例如,这里定义了一个泛型类: class MyCollection<T> ...

随机推荐

  1. Missing artifact com.oracle:ojdbc14:jar:10.2.0.1.0

    问题说明:导入Maven项目时,想要添加Oracle驱动包时,Maven的pom.xml总是报Missing artifact com.oracle:ojdbc14:jar:10.2.0.1.0错. ...

  2. linux安装Nginx 以及 keepalived 管理Nginx

    linux安装Nginx 1.1将Nginx素材内容上传到/usr/local目录(pcre,zlib,openssl,nginx)(注意:必须登录用对这个文件具有操作权限的) 1.2安装pcre库 ...

  3. Android记事本在菜单栏添加搜索按钮方法

    效果图 这个app结构和我之前将记事本开发的博客基本一致,我这里直接讲一下怎样添加 使用的开发软件为android studio 首先在res目录下新建文件夹menu,添加目录布局文件main_men ...

  4. docker镜像alpine封装nginx1.16.1【dockerfile】

    github地址:https://github.com/laileman/Docker/Dockerfile/alpine-nginx1.16.1 1-目录结构 2- dockerfile内容 3- ...

  5. webkit 技术内幕 笔记 二

    浏览器历史 80年代末-90年代初:worldwideweb(nexus) -- Berners-Lee 1993: Mosaic浏览器,后来叫网景(Netscape)--Marc Andreesse ...

  6. 安装Ansible到CentOS(YUM)

    运行环境 系统版本:CentOS Linux release 7.3.1611 (Core) 软件版本:ansible 硬件要求:无 安装过程 1.安装YUM-EPEL源 HTTP-Tools软件包由 ...

  7. 记一个js toUpperCase函数 大小写特性

    toUpperCase()是javascript中小写变大写的函数 "ı".toUpperCase() == 'I',"ſ".toUpperCase() == ...

  8. 深入浅出Mybatis系列五-TypeHandler简介及配置(mybatis源码篇)

    注:本文转载自南轲梦 注:博主 Chloneda:个人博客 | 博客园 | Github | Gitee | 知乎 上篇文章<深入浅出Mybatis系列(四)---配置详解之typeAliase ...

  9. 【android】Parcelable的相关技术总结

    关于Parcelable的相关知识学习   进行Android开发的时候,无法将对象的引用传给Activities或者Fragments,我们需要将这些对象放到一个Intent或者Bundle里面,然 ...

  10. 关于JavaScript的原型继承与原型链

    在讨论原型继承之前,先回顾一下关于创建自定义类型的方式,这里推荐将构造函数和原型模式组合使用,通过构造函数来定义实例自己的属性,再通过原型来定义公共的方法和属性. 这样一来,每个实例都有自己的实例属性 ...