实例化一个泛型类型? [英] Instantiating a generic type?

查看:259
本文介绍了实例化一个泛型类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前工作的一个泛型集合类,我想创建一个返回从集合对象的方法。如果特定对象不集合然后应当创建的对象中存在的,添加到集合中,然后返回

I'm currently working on a generic collection class and I'd like to create a method which returns an object from the collection. If the specific object does not exist in the collection then the object should be created, added to the collection, and then returned.

我现在遇到了一些问题,但。泛型集合,如果其中再presents一个抽象类,我无法实例化的类型。

I'm encountering a few problems though. The generic collection if of a type which represents an abstract class and I'm having trouble instantiating that.

下面是我的类定义:

public class CacheCollection<T> : List<CacheItem<T>> where T : EntityBase

和这里的部分​​完成的方法上我的工作:

And here's the partially complete method on which I am working:

public T Item(int Id)
{
    CacheItem<T> result = this.Where(t => t.Entity.Id == Id).First();

    if (result == null) //item not yet in cache, load it!
    {
        T entity = new T(Id); //design time exception here: Cannot create an instance of the variable type 'T' because it does not have the new() constraint
        result = new CacheItem<T>(entity);
        this.Add(result);
    }

    return result.Entity;
}

如何解决这个任何想法?

Any ideas on how to get around this?

编辑:从EntityBase派生的所有类都标识为只读属性。

All classes derived from EntityBase have Id as a read-only property.

推荐答案

更新2 :那么,你,你有没有定义的非一般评论说 CacheCollection 类型;但你去说,你有一个词典&LT;类型,CacheCollection&GT; 。这些陈述不能同时是真实的,所以我猜测,由 CacheCollection 你的意思是 CacheCollection&LT; EntityBase&GT;

UPDATE 2: Well, you say in a comment that you have not defined a non-generic CacheCollection type; but then you go on to say that you have a Dictionary<Type, CacheCollection>. These statements cannot both be true, so I am guessing that by CacheCollection you mean CacheCollection<EntityBase>.

现在,这里的问题: X&LT;衍生GT; 不能转换为 X&LT;基地&GT; 如果 X&LT; T&GT; 键入是不是协变。也就是说,在您的情况下,仅仅因为 T EntityBase 并不意味着得出结论说 CacheCollection&LT ; T&GT; 派生自 CacheCollection&LT; EntityBase&GT;

Now here's the problem: a X<Derived> cannot be cast to a X<Base> if the X<T> type is not covariant. That is, in your case, just because T derives from EntityBase does not mean that CacheCollection<T> derives from CacheCollection<EntityBase>.

对于为什么这是一个具体的例子,考虑名单,其中,T&GT; 键入。假设你有一个名单,其中,串&GT; 名单,其中,对象&gt; 字符串对象派生,但它并不意味着名单,其中,串&GT; 名单,其中,对象&gt; ;如果没有,那么你可以有code是这样的:

For a concrete illustration of why this is, consider the List<T> type. Say you have a List<string> and a List<object>. string derives from object, but it does not follow that List<string> derives from List<object>; if it did, then you could have code like this:

var strings = new List<string>();

// If this cast were possible...
var objects = (List<object>)strings;

// ...crap! then you could add a DateTime to a List<string>!
objects.Add(new DateTime(2010, 8, 23));

幸运的是,解决这个问题的方法(在我看来)是pretty的简单。基本上,通过定义的非通用基础类,还有我原来的建议,从 CacheCollection&LT; T&GT; 将获得。更重要的是,去用一个简单的非通用接口。

Fortunately, the way around this (in my view) is pretty straightforward. Basically, go with my original suggestion by defining a non-generic base class from which CacheCollection<T> will derive. Better yet, go with a simple non-generic interface.

interface ICacheCollection
{
    EntityBase Item(int id);
}

(看看我的新code以下,看看如何在您的泛型类型实现这个接口)。

(Take a look at my updated code below to see how you can implement this interface in your generic type).

那么对于你的字典,而不是一个词典&LT;类型,CacheCollection&LT; EntityBase&GT;&GT; ,把它定义为一个词典&LT;类型,ICacheCollection&GT ;。和你的code,其余应该团结起来

Then for your dictionary, instead of a Dictionary<Type, CacheCollection<EntityBase>>, define it as a Dictionary<Type, ICacheCollection> and the rest of your code should come together.

更新:看来你是从我们隐瞒!所以,你有一个非通用 CacheCollection 基类, CacheCollection&LT; T&GT; 导出,我说的对

UPDATE: It seems that you were withholding from us! So you have a non-generic CacheCollection base class from which CacheCollection<T> derives, am I right?

如果我对你的最新的评论这个答案的理解是正确的,这是我给你的忠告。写一个类来提供间接访问该词典&LT;类型,CacheCollection&GT; 的你。通过这种方式,你可以有许多 CacheCollection&LT; T&GT; 在不牺牲类型安全实例

If my understanding of your latest comment to this answer is correct, here's my advice to you. Write a class to provide indirect access to this Dictionary<Type, CacheCollection> of yours. This way you can have many CacheCollection<T> instances without sacrificing type safety.

这样的事情(注意:code此基础上改装的的更新上面):

Something like this (note: code modified based on new update above):

class GeneralCache
{
    private Dictionary<Type, ICacheCollection> _collections;

    public GeneralCache()
    {
        _collections = new Dictionary<Type, ICacheCollection>();
    }

    public T GetOrAddItem<T>(int id, Func<int, T> factory) where T : EntityBase
    {
        Type t = typeof(T);

        ICacheCollection collection;
        if (!_collections.TryGetValue(t, out collection))
        {
            collection = _collections[t] = new CacheCollection<T>(factory);
        }

        CacheCollection<T> stronglyTyped = (CacheCollection<T>)collection;
        return stronglyTyped.Item(id);
    }
}

这将使你写code这样的:

This would allow you to write code like the following:

var cache = new GeneralCache();

RedEntity red = cache.GetOrAddItem<RedEntity>(1, id => new RedEntity(id));
BlueEntity blue = cache.GetOrAddItem<BlueEntity>(2, id => new BlueEntity(id));


那么,如果 T EntityBase 派生,但没有一个参数的构造函数,你最好的选择是要可以指定一个工厂方法,将生成一个 T 中相应的参数的 CacheCollection&LT; T&GT; 构造


Well, if T derives from EntityBase but does not have a parameterless constructor, your best bet is going to be to specify a factory method that will generate a T for the appropriate parameters in your CacheCollection<T> constructor.

这样的(注意:code此基础上改装的的更新上面):

Like this (note: code modified based on new update above):

public class CacheCollection<T> : List<CacheItem<T>>, ICacheCollection where T : EntityBase
{
    private Func<int, T> _factory;

    public CacheCollection(Func<int, T> factory)
    {
        _factory = factory;
    }

    // Here you can define the Item method to return a more specific type
    // than is required by the ICacheCollection interface. This is accomplished
    // by defining the interface explicitly below.
    public T Item(int id)
    {
        // Note: use FirstOrDefault, as First will throw an exception
        // if the item does not exist.
        CacheItem<T> result = this.Where(t => t.Entity.Id == id)
            .FirstOrDefault();

        if (result == null) //item not yet in cache, load it!
        {
            T entity = _factory(id);

            // Note: it looks like you forgot to instantiate your result variable
            // in this case.
            result = new CacheItem<T>(entity);

            Add(result);
        }

        return result.Entity;
    }

    // Here you are explicitly implementing the ICacheCollection interface;
    // this effectively hides the interface's signature for this method while
    // exposing another signature with a more specific return type.
    EntityBase ICacheCollection.Item(int id)
    {
        // This calls the public version of the method.
        return Item(id);
    }
}

我也建议,如果您的项目将拥有唯一的ID,使用词典℃的,INT,CacheItem&LT; T&GT;&GT; 作为后备存储,而不是一个名单,其中,CacheItem&LT; T&GT;&GT; ,因为它会让你的项目查找O(1)而不是O(N)

I would also recommend, if your items are going to have unique IDs, to use a Dictionary<int, CacheItem<T>> as your backing store instead of a List<CacheItem<T>> as it will make your item lookup O(1) instead of O(N).

(我也建议使用私有成员举行集合本身执行这一类,而不是从收集直接继承,因为使用继承暴露了你可能想隐藏的如添加功能插入,等等。)

(I would also recommend implementing this class using a private member to hold the collection itself rather than inheriting from the collection directly, as using inheritance exposes functionality you probably want hidden such as Add, Insert, etc.)

这篇关于实例化一个泛型类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆