C# 泛型类构造函数调用的困境
我有这样一个通用的单例:C# 泛型类构造函数调用的困境,c#,constructor,initialization,generics,C#,Constructor,Initialization,Generics,我有这样一个通用的单例: 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))
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.
}
}
var type = typeof(List<String>);
object list = Activator.CreateInstance(type, /* capacity */ 20);
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
公共类缓存
{
专用字典缓存块;
//构造函数之类的东西,这是一个单例
公共T GetCache(Guid id)
{
如果(!cachedBlocks.ContainsKey(id))
cachedBlocks.Add(id,LoadFromSharePoint(id))
返回cachedBlocks[id];
}
公共T LoadFromSharePoint(Guid id)
{
returnnewt(id)//问题出在这里。
}
}
错误消息是:
无法创建类型T的实例,因为它没有new()约束
我必须提到,我必须传递
id
参数,并且没有其他方法可以这样做。任何关于如何解决此问题的想法都将受到高度赞赏。通常,您会将类型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;
}
当然,您可能需要在之后执行一些强制转换(到
T
)。要执行此操作,您应该指定T
是什么。你的缓存可以容纳任何东西吗<代码>老虎
,冰箱
和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:Cacheable,new()
{
专用字典缓存块;
//构造函数之类的东西,这是一个单例
公共T GetCache(Guid id)
{
如果(!cachedBlocks.ContainsKey(id))
cachedBlocks.Add(id,LoadFromSharePoint(id))
返回cachedBlocks[id];
//您首先检查是否存在,然后添加到其中
//它再次执行相同的检查,然后返回
//键的值,必须再次查看该值。
//如果可以,您可以直接返回
//return cachedBlocks[id]=LoadFromSharePoint(id);
//如果您的LoadFromSharePoint没有那么昂贵。
//请注意,这和你原来的有点不同
//关于它做什么的方法。
}
公共T LoadFromSharePoint(Guid id)
{
返回新的T{Key=id};//这里不再有问题了。
}
}
可缓存的公共接口
{
Guid键{get;set;}
}
现在从接口
Cacheable
派生所有可缓存项(无论您将为Cache
传递什么T),以便使用泛型类型的构造函数而不受任何约束,并且在类中,需要使用语法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 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.
}
}
var type = typeof(List<String>);
object list = Activator.CreateInstance(type, /* capacity */ 20);
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
Foo fooObj=new Foo();
Book aBook=fooObj.oneEmptyElement();
aBook.name=“Emma”;
Book anotherBook=fooObj.setAttribute(“名称”、“约翰”);
List-aListOfBooks=fooObj.ListofToEmptYelements();
aListOfBooks[0]。name=“Mike”;
aListOfBooks[1]。name=“Angelina”;
Console.WriteLine(aBook.name)//输出Emma
Console.WriteLine(另一本书的名称)//输出约翰
Console.WriteLine(aListOfBooks[0].name);//输出话筒
Console.WriteLine(aListOfBooks[1].name);//输出安吉丽娜
这听起来是个不错的主意,但我不能说value.ID=ID,它只是不让我,尽管我很快就能得到它。还有其他建议吗?顺便说一下,非常感谢:)@AlexOltean我的答案的第二部分是另一个选择,因为当你不能说value.ID=ID
时。试试看:D@AlexOltean虽然这个答案可能有效,但它实际上根本不是正确的方法。反思在这里是完全没有道理的。除了速度较慢之外,这不是正确的方法。您的代码在没有反射的情况下更能表达它所做的事情。通过反思,你让事情变得模糊不清。随着时间的推移,你会明白的。@nawfal我不赞成反思。我的第一个建议基本上与你的相同,但你在类中展示了它,并带有一个接口。我从字面上解释了“我必须传递那个id参数,没有其他方法可以传递”,然后唯一的解决方案是反射,你必须同意。这也会起作用,特别是因为我会避免使用reflection@AlexOltean很高兴它起作用了。我在另一篇帖子上发表了评论,没有看到你的评论。Cheers@AlexOltean我编辑了我的答案,你可以用我的建议加快你的代码。只是现在它每次都更新对应于id的值(如果id键存在)并一次性返回它。这取决于从SharePoint加载的有多贵,我认为这一点都不贵。相关问题: