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加载的
有多贵,我认为这一点都不贵。相关问题: