2012-09-29 53 views
0
// EF (Model) project 
class EntityBase { } // base class for all types 
class Person : EntityBase // specific implementation for type Person 

// ViewModel project 
class EditableViewModel<T> where T : EntityBase // base class for all viewmodel types 
class PersonViewModel : EditableViewModel<Person> 
class CollectionViewModel<T> where T : EditableViewModel<EntityBase> // base class that handles CRUD operation on EditableViewModel<T> collections 

// everything up to this point work. I am unable to create specific instance of CollectionViewModel<> 
class AllPersonsViewModel : CollectionViewModel<PersonViewModel> 

我该如何做到这一点?通用类型作为泛型类型参数

+0

问题是在最后的评论,fyi。 – usr

+0

也许他没有时间阅读评论,但确实有时间倒计时。然后他决定删除他的评论,发现它“不适合”。 :) – Goran

回答

1

如果你愿意使用接口而不是类,你可以很容易地做协变。下面的代码编译得很好:

class EntityBase { } 
class Person : EntityBase {} 

interface EditableViewModel<out T> where T : EntityBase {} // Must be an interface. "out" marks T as a covariant parameter 
class PersonViewModel : EditableViewModel<Person> {} 
class CollectionViewModel<T> where T : EditableViewModel<EntityBase> { } 

class AllPersonsViewModel : CollectionViewModel<PersonViewModel> { } 
1

您得自CollectionViewModel<PersonViewModel>,但您将T限制为EditableViewModel<EntityBase>PersonViewModelEditableViewModel<Person>,但它不是EditableViewModel<EntityBase>。这两种类型是无关的。

他们为什么不相关?示例:如果B与A分配兼容,则List<B>List<A>不是分配兼容的。

如果您想了解更多关于此研究的主题,请在C#中使用co-和contravariance。

+0

所以,这意味着我可以对泛型集合类型本身做协变,但不能在类型参数上做到这一点?有没有办法解决这个问题,所以我可以达到以上的层次? – Goran

+0

不知道它是否可以实现,因为我没有这方面的经验。无论如何,你需要引入接口,因为只有接口可以是变体(和委托)。这会变得肮脏,每个动态的语言家伙都会嘲笑你:“我们不需要这样的恶臭,只是为了关闭编译器!” ;-)也许这是暗示你已经离开了推荐路径。 – usr

+0

@usr ...或者,您可以引入第二个类型参数。那么你不需要担心接口(尽管使用接口通常会提供更多的灵活性)。 – phoog

1

可以由此实现这一点:

class CollectionViewModel<TEntity, TViewModel> 
    where TViewModel : EditableViewModel<TEntity> 
    where TEntity : EntityBase 

class AllPersonsViewModel : CollectionViewModel<Person, PersonViewModel> 

随着USR的回答意味着,如果你限制了类型接口而不是抽象基类,你会得到更多的灵活性;如果界面是共同的或逆变的,则这是尤其如此。