具有非泛型方法约束的泛型类
本文关键字:泛型类 约束 泛型方法 | 更新日期: 2023-09-27 18:29:24
我有这个类作为我的存储库:
public class Repository<T> where T : class, new()
{
public T GetByID(int id)
{
//Code...
}
}
但在一些情况下,我不想留下类的默认公共构造函数(例如一些需要一些逻辑的特定模型属性),比如:
public class Person
{
public CPersonID PersonID { get; private set; }
//This shouldn't exist outside Person, and only Person knows the rules how to handle this
public class CPersonID
{
internal CPersonID() { }
}
}
这使得Repository模板类由于new()
约束而无效。我想做这样的东西:
public class Repository<T> where T : class
{
//This function should be created only when the T has new()
public GetByID(int id) where T : new()
{
}
//And this could be the alternative if it doesn't have new()
public GetByID(T element, int id)
{
}
}
我有什么办法可以做到这一点吗?
编辑:Get
方法示例:
public IList<T> GetAll()
{
IList<T> list = new List<T>();
using(IConnection cn = ConnectionFactory.GetConnection())
{
ICommand cm = cn.GetCommand();
cm.CommandText = "Query";
using (IDataReader dr = cm.ExecuteReader())
{
while(dr.Read())
{
T obj = new T(); //because of this line the class won't compile if I don't have the new() constraint
//a mapping function I made to fill it's properties
LoadObj(obj, dr);
list.Add(obj);
}
}
}
return list;
}
给定public class Repository<T> where T : class
,您不能定义只有当T
具有无参数构造函数时才存在的实例方法。你不需要那个。你只需要repository.GetByID(3)
就可以工作了。如果GetByID
是一个实例方法,那么它也可以工作,但如果它是一个扩展方法,并且扩展方法可以向T
添加需求。
public static class RepositoryExtensions
{
public T GetByID(this Repository<T> repo, int id) where T : class, new()
{
...
}
}
请注意,如果已经存在同名的实例方法,则扩展方法不起作用,因此,如果使用此方法,则需要GetByID
的两个重载都是扩展方法,而不仅仅是此重载。
实际的逻辑属于Repository
类,但您可以转发到:
public class Repository<T> where T : class
{
internal T GetByIDImpl(int id, Func<T> factory)
{
...
}
}
public static class RepositoryExtensions
{
public T GetByID(this Repository<T> repo, int id) where T : class, new()
{
return repo.GetByIDImpl(id, () => new T());
}
public T GetByID(this Repository<T> repo, T element, int id) where T : class
{
return repo.GetByIDImpl(id, () => element);
}
}
不,你不能这样做。
所有约束都必须在引入泛型参数的地方指定,在本例中是在类级别。
因此,您有两种选择:
- 添加
, new()
作为约束,将存储库类的使用限制为使用具有公共无参数构造函数的类型 - 不将其添加为约束,而是使用反射尝试在运行时构造对象
请注意,如果类型没有有效的构造函数,则第2点可能会失败(在运行时)。
没有办法要求编译器创建一个类,在该类中,调用特定方法的能力是有条件的,即"只有当类型有构造函数时,才让我调用GetByID"。
如果您想将其作为编译时间约束,可以执行
public class Class<T> where T : class
{
public void Method<U> where U : T, new()
{
// ...
}
}
但这有一个缺点,那就是你必须进行
new Class<HasConstructor>().Method<HasConstructor>();
因为该类型不会被隐式地拾取。优点是以下内容不会编译:
new Class<NoConstructor>().Method<NoConstructor>();