[英]Generic class with non-generic method constraint?
我將此類用作我的存儲庫:
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() { }
}
}
由於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;
}
正如Lasse V. Karlsen已經回答的那樣,這不可能直接實現。 但是,您可以獲得非常接近的距離,足夠接近實際用途。
給定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沒有有效的構造函數,則第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>();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.