在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制。如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。这些限制称为约束。约束是使用 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. Wannafly Winter Camp 2020 Day 6C 酒馆战棋 - 贪心

    你方有 \(n\) 个人,攻击力和血量都是 \(1\).对方有 \(a\) 个普通人, \(b\) 个只有盾的,\(c\) 个只有嘲讽的,\(d\) 个有盾又有嘲讽的,他们的攻击力和血量都是无穷大.有 ...

  2. ng--tolist说明

    起步 下载模板: git clone https://github.com/tastejs/todomvc-app-template.git --depth 1 初始化项目: ng new todom ...

  3. 在Django中使用Sentry(Python 3.6.8 + Django 1.11.20 + sentry-sdk 0.13.5)

    1. 安装Sentry pip install sentry-sdk==0.13.5 2.在settings.py中配置 sentry_sdk.init( dsn="https://**** ...

  4. javascript 权威指南一

    1. JavaScript是面向web(网页)的编程语言. 2.html: 描述网页内容,css:描述网页样式,JavaScript:描述网页行为 3.JavaScript非常适合面向对象和函数式的编 ...

  5. IO流学习之File类

    File类 Java文件类以抽象的方式代表文件名和目录路径名.该类主要用于文件和目录的创建.文件的查找和文件的删除等. File对象代表磁盘中实际存在的文件和目录.就是把文件和目录转换成对象,读取到内 ...

  6. ntoskrnl.exe导致蓝屏解决方法

    背景 博主电脑近段时间经常蓝屏,主要表现在开关机.重启等操作上: 使用 BlueScreenView 查看C:\Windows\Minidump下的bmp文件,关键信息如下: 解决方法 查阅网上的各种 ...

  7. 《Photoshop 2020》初心版_v6 21.0.2.57

    <Phtoshop 2020>初心版_v6 下载地址(5245) SHA1:E926A1B99D147A27A44050A5BCE2E69E2CDAEEAE 版本信息    发行版本 20 ...

  8. 原生JS操作class 极致版

    // 获取class function getClass(el) { return el.getAttribute('class') } // 设置class function setClass(el ...

  9. java下的slf4j

    一.导读 我们使用log4j框架时,经常会用slf4j-api.在运行时,经常会遇到如下的错误提示: ? 1 2 3 4 5 SLF4J: Class path contains multiple S ...

  10. Codeforces 540A - Combination Lock

    Scrooge McDuck keeps his most treasured savings in a home safe with a combination lock. Each time he ...