c# – 实例化泛型类型?
我目前正在研究泛型集合类,我想创建一个从集合中返回对象的方法.如果集合中不存在特定对象,则应创建对象,将其添加到集合中,然后返回.
我遇到了一些问题.泛型集合if if表示抽象类的类型,我在实例化时遇到问题. 这是我的班级定义: public class CacheCollection<T> : List<CacheItem<T>> where T : EntityBase 这是我工作的部分完整的方法: 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; } 关于如何解决这个问题的任何想法? 编辑:从EntityBase派生的所有类都将Id作为只读属性. 解决方法
更新2:嗯,你在评论中说你没有定义非通用的CacheCollection类型;但接着你继续说你有一个字典< Type,CacheCollection>.这些语句不可能都是真的,所以我猜通过CacheCollection你的意思是CacheCollection< EntityBase>.
现在问题在于:X< Derived>不能转换为X< Base>如果X< T>在你的情况下,只是因为T派生自EntityBase并不意味着CacheCollection< T>派生自CacheCollection< EntityBase>. 为了具体说明原因,考虑List< T>.类型.假设你有一个List< string>和一个List< object>. string派生自object,但它不遵循List< string>派生自List< object> ;;如果确实如此,那么你可以拥有这样的代码: 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)); 幸运的是,围绕这个(在我看来)的方式是非常简单的.基本上,通过定义一个非通用基类来实现我的原始建议,CacheCollection< T>将衍生出来.更好的是,使用简单的非通用接口. interface ICacheCollection { EntityBase Item(int id); } (请查看下面的更新代码,了解如何在通用类型中实现此接口). 然后,对于您的字典,而不是字典< Type,CacheCollection< EntityBase>>,将其定义为字典< Type,ICacheCollection>而其余的代码应该结合在一起. 更新:您似乎拒绝了我们!所以你有一个非通用的CacheCollection基类,CacheCollection< T>派生,我是对的吗? 如果我对您对此答案的最新评论的理解是正确的,这是我对您的建议.编写一个类来提供对此Dictionary的间接访问< Type,CacheCollection>你的.通过这种方式,您可以拥有许多CacheCollection< T>不牺牲类型安全的情况. 这样的事情(注意:基于上面的新更新修改的代码): 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); } } 这将允许您编写如下代码: 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但没有无参数构造函数,那么最好的办法是指定一个工厂方法,它将为CacheCollection< T>中的相应参数生成一个T.构造函数. 像这样(注意:根据上面的新更新修改代码): 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,我还建议使用Dictionary< int,CacheItem< T>>作为您的后备存储而不是List< CacheItem< T>>因为它会使你的项目查找O(1)而不是O(N). (我还建议使用私有成员来实现此类来保存集合本身而不是直接从集合继承,因为使用继承公开了您可能想要隐藏的功能,例如Add,Insert等) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |