简体   繁体   中英

Generic type as generic type argument

// 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>

How can I achieve this?

You are deriving from CollectionViewModel<PersonViewModel> but you restricted T to be a EditableViewModel<EntityBase> . PersonViewModel is a EditableViewModel<Person> , but it is not a EditableViewModel<EntityBase> . The two types are unrelated.

Why are they unrelated? Example: If B is assignment-compatible to A, then List<B> is not assignment-compatible to List<A> .

If you want to know more about this research the topic of co- and contravariance in C#.

You can achieve this thus:

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

class AllPersonsViewModel : CollectionViewModel<Person, PersonViewModel> 

As usr's answer implies, you would get more flexibility if you constrain the types to interfaces rather than abstract base classes; this is especially true if the interface is co- or contravariant.

You can do covariance easily enough if you're willing to work with interfaces instead of classes. The following code compiles fine:

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> { }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM