在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制。如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。这些限制称为约束。约束是使用 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. 对Linux内核tty设备的一点理解(转)

    虽然一直做嵌入式Linux,宿主机和开发板通信天天都在用tty设备通信,但是其实自己对TTY设备及终端的概念认识几乎是0.对于Linux内核的终端.tty.控制台等概念的认识很模糊.由于在学习的时候碰 ...

  2. C++->10.3.2-3,使用文件流类录入数据,并统计行数

    题目:建立一个文本文件,从键盘录入一篇短文存放在该文件中短文由若干行构成,每行不超过80个字符,并统计行数. /* #include<iostream.h>#include<stdl ...

  3. JS变量+作用域

    基本类型-栈内存 保存基本类型的变量保存的是值本身 引用类型-堆内存 保存引用类型的变量保存的并不是对象本身,而是一个指向该对象的引用地址 引用类型判断对象是否相等 function equalObj ...

  4. LeetCode 13、罗马数字转整数

    罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值I 1V 5X 10L 50C 100D 500M 1000例如, 罗马数字 2 写做 II ,即为两个并列的 1.12 ...

  5. 无法解析的外部符号 _snprintf

    VS2010下: 在使用第三方静态库 遇到无法解析的外部符号 _snprintf . 编译第三方库的时候 看到有 warning C4013: 'snprintf' undefined; assumi ...

  6. PAT - A1073

    1073 Scientific Notation (20point(s)) 小数点移动的边界条件 小数点左移 超过数据左边界 小数点右移 未超过数据右边界 超过数据右边界 +0.1E+2 --> ...

  7. Dev 控件笔记1 repositoryItemLookUpEdit 控件

            repositoryItemLookUpEdit 嵌套在 gridcontrol 中 作为列下拉 效果就是多列的 combox 代码如下 var y = userinfo.Select ...

  8. Dubbo服务暴露分析

    Dubbo的服务暴露是一个重要的特性,了解其机制很重要.之前有很多人写了有关的源代码分析,在本文中不再重新分析.官方文档中的一篇写的就很好,本文主要是有关内容进行补充与总结. 传送门:服务导出 为什么 ...

  9. Spark学习之路 (一)Spark初识 [转]

    官网介绍 什么是Spark 官网地址:http://spark.apache.org/ Apache Spark™是用于大规模数据处理的统一分析引擎. 从右侧最后一条新闻看,Spark也用于AI人工智 ...

  10. spring框架中用到了哪些设计模式

    1.代理模式:在AOP和remoting中被用的比较多 2.单例模式:在spring配置文件中定义的bean默认为单例模式 3.模板方法模式:解决代码重复问题 4.前端控制器模式:spring提供了D ...