i have generic interface, , class implementing interface concrete type parameter. have generic class using generic interface type constraint, type parameter restricted subclass of base class. want instance generic class class implementing interface have problem of converting class interface. following code illustrates classes mentioned:
the base class:
class domainbase { }
the class used type parameter in interface
class person : domainbase { }
the generic interface:
public interface irepository<t> t : class { ienumerable<t> fetch(); t persist(t item); }
the class implementing generic interface:
class personrepository : irepository<person> { public ienumerable<person> fetch() { ... } public person persist(person item) { ... } }
the generic class using generic interface:
class domainbaseviewmodel<repository> repository : irepository<domainbase>, new() { private repository repository = new repository(); private observablecollection<domainbase> items; }
however, following line can't compiled because personrepository unable converted irepository<domainbase>:
var viewmodel = new domainbaseviewmodel<personrepository>();
although can solve issue covariance disallows use of type parameter in parameter lists:
public interface irepository<out t> t : class { ... t persist(object item); } class personrepository : irepository<person> { public person persist(object item) { ... } }
so have convert parameter person, compromises type safety.
is there better way allow covariance , use of type parameter in parameter lists in case?
no - whole point of restriction on covariance guarantees safety. personrepository
isn't irepository<domainbase>
because can't ask persist arbitrary domainbase
object. expect code do?
class product : domainbase {} ... irepository<domainbase> repository = new personrepository(); repository.persist(new product());
personrepository
doesn't know how persist product
values.
if in cases need "read" parts of repository interface, call out explicitly:
public interface irepositoryreader<out t> { ienumerable<t> fetch(); } public interface irepository<t> : irepositoryreader<t> { t persist(t item); }
then domainbaseviewmodel
class be:
class domainbaseviewmodel<trepository> trepository : irepositoryreader<domainbase>, new() { private trepository repository = new trepository(); private observablecollection<domainbase> items; }
that doesn't work if want domainbaseviewmodel
persist items though. in case, perhaps should generic in type of model well:
class domainbaseviewmodel<trepository, tentity> trepository : irepository<tentity>, new() { private trepository repository = new repository(); private observablecollection<tentity> items; }
then:
var viewmodel = new domainbaseviewmodel<personrepository, person>();