我有这个通用单例,如下所示:
public class Cache<T>
{
private Dictionary<Guid, T> cachedBlocks;
// Constructors and stuff, to mention this is a singleton
public T GetCache(Guid id)
{
if (!cachedBlocks.ContainsKey(id))
cachedBlocks.Add(id, LoadFromSharePoint(id))
return cachedBlocks[id];
}
public T LoadFromSharePoint(Guid id)
{
return new T(id) // Here is the problem.
}
}
错误消息是:
无法创建类型为T的实例,因为它没有new()约束。
我必须提到我必须传递id
参数,并且没有其他方法可以这样做。关于如何解决这个问题的任何想法都将受到高度赞赏。
答案 0 :(得分:14)
通常,您会将类型T
约束为具有默认构造函数的类型并调用它。然后,您必须添加方法或属性才能为实例提供id
的值。
public static T LoadFromSharePoint<T>(Guid id)
where T : new() // <-- Constrain to types with a default constructor
{
T value = new T();
value.ID = id;
return value;
}
或者,因为您指定 通过构造函数提供id
参数,您可以使用反射调用参数化构造函数。 您必须确保该类型定义了您要调用的构造函数。您不能将泛型类型T
约束到具有除默认构造函数之外的特定构造函数的类型。 (例如where T : new(Guid)
不起作用。)
例如,我知道 new List<string>(int capacity)
上有一个构造函数List<T>
,可以像这样调用:
var type = typeof(List<String>);
object list = Activator.CreateInstance(type, /* capacity */ 20);
当然,您可能希望之后进行一些投射(T
)。
答案 1 :(得分:4)
为此,您应指定T
是什么。你的Cache<T>
能举办什么吗? Tiger
,Fridge
和int
也是如此?那不是一个合理的设计。你应该约束它。您需要一个T
的实例,它将使用Guid
来构造实例。这不是通用T
。它非常具体T
。将您的代码更改为:
public class Cache<T> where T : Cacheable, new()
{
private Dictionary<Guid, T> cachedBlocks;
// Constructors and stuff, to mention this is a singleton
public T GetCache(Guid id)
{
if (!cachedBlocks.ContainsKey(id))
cachedBlocks.Add(id, LoadFromSharePoint(id))
return cachedBlocks[id];
//you're first checking for presence, and then adding to it
//which does the same checking again, and then returns the
//value of key again which will have to see for it again.
//Instead if its ok you can directly return
//return cachedBlocks[id] = LoadFromSharePoint(id);
//if your LoadFromSharePoint is not that expensive.
//mind you this is little different from your original
//approach as to what it does.
}
public T LoadFromSharePoint(Guid id)
{
return new T { Key = id }; // Here is no more problem.
}
}
public interface Cacheable
{
Guid Key { get; set; }
}
现在从界面T
派生所有可缓存的(可以为Cache<T>
传递的Cacheable
)。
答案 2 :(得分:0)
为了在没有任何约束的情况下使用Generic Type的构造函数,并且在类中,需要使用语法,其中T:class,new()
这可以根据使用的目标类在运行时更改属性(字段)的值 - 不仅是获取/设置属性
首先,声明泛型类:
public class Foo<T> where T : class, new()
{
public T oneEmptyElement()
{
return new T();
}
public T setAttribute(string attributeName, string attributeValue)
{
T objT = new T();
System.Reflection.FieldInfo fld = typeof(T).GetField(attributeName);
if (fld != null)
{
fld.SetValue(objT, attributeValue);
}
return objT;
}
public List<T> listOfTwoEmptyElements()
{
List<T> aList = new List<T>();
aList.Add(new T());
aList.Add(new T());
return aList;
}
}
然后声明一个潜在的目标类:
public class Book
{
public int name;
}
最后,呼叫可以像这样完成:
Foo<Book> fooObj = new Foo<Book>();
Book aBook = fooObj.oneEmptyElement();
aBook.name = "Emma";
Book anotherBook = fooObj.setAttribute("name", "John");
List<Book> aListOfBooks = fooObj.listOfTwoEmptyElements();
aListOfBooks[0].name = "Mike";
aListOfBooks[1].name = "Angelina";
Console.WriteLine(aBook.name); //Output Emma
Console.WriteLine(anotherBook.name); //Output John
Console.WriteLine(aListOfBooks[0].name); // Output Mike
Console.WriteLine(aListOfBooks[1].name); // Output Angelina