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