10

我有一个看起来像这样的通用单例:

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参数,而且没有其他方法可以这样做。任何关于如何解决这个问题的想法都将受到高度赞赏。

4

3 回答 3

21

通常,您会将类型限制为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之后进行一些转换 (to )。

于 2013-02-21T13:13:36.717 回答
5

为此,您应该指定是什么T。你Cache<T>能装什么吗?TigerFridge以及int?那不是声音设计。你应该约束它。您需要一个实例TGuid构造实例。那不是通用的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

于 2013-02-21T13:26:46.037 回答
0

为了在没有任何约束的情况下使用泛型类型的构造函数,并且在类中,需要使用语法where 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
于 2017-01-24T11:40:51.087 回答