generics - Using Covariance with an Interface Base Type in .NET 4? -
i have entities created linq-to-sql. 6 of these entities (representing values in drop-down lists) implement interface i've called ivalue
. did because ui layer going have account couple special cases -- notably, display if original value on record has been flagged deleted.
the repository has variety of listallxxx
methods these guys. of these return generic lists typed appropriate entity type. example:
public static list<contacttype> listallcontacttypes(deletedoptions getdeleted) { /* requisite code */ }
contacttype
implement ivalue
, of course.
there's set of services designed retrieve ui-specific list. basic pattern thus:
// 1 of these each entity type public static list<ivalue> getcontacttypelist(contacttype target) { list<ivalue> ret = lovrepository.listallcontacttypes(deletedoptions.nodeleted); preplist(ret, target); return ret; } // of above methods use guy private static void preplist(list<ivalue> list, ivalue targetentity) { list.insert(0, new dummyvalue() { description = "add new ... ", id = 0 }); if (targetentity != null && !(list.contains(targetentity)) list.add(new dummyvalue() { description = "[deleted]", id = -1 }); }
(i should note dummyvalue
simple class created implements ivalue
, , whole purpose in life serve "add new" , "deleted" menu options.)
all of comes because didn't want write few dozen lines of identical code -- whole reason thought had covariance.
the code written here not compile. i've tried manual cast list<ivalue>
on listallcontacttypes
line; compiles, fails @ run-time invalid cast exception.
how can want go here? there limitation on using generic variance interfaces? if so, there easy way around it? if not, relegated writing bunch of highly-repetitive-but-just-slightly-different code? (which i'm really trying avoid.)
this may duplicate, google-fu failing me right now. if is, please vote close accordingly. (i'll pile on close vote if that's case!)
co- , contravariance can used on delegate , interface declarations, code won't work. can cast result using cast extension method, , make code work:
list<ivalue> ret = lovrepository.listallcontacttypes(deletedoptions.nodeleted) .cast<ivalue>().tolist();
this casts each element in list , creates new list of ivalue elements.
the reason why need this, has type safety. in example code of course, there no problem. method listallcontacttypes declared return type list<contacttype>. if assign list<ivalue>, can put ivalue in - if other code expects list contain contacttype explicitly, code break. consider example:
list<contacttype> listofcontacttype = // method .... list<ivalue> list = listofcontacttype; // line not allowed.
if compiled, able do:
list.insert(0,new dummytype());
but still have consider original reference, on should allowed do:
contacttype contact = listofcontacttype[0]; // woops, element not contacttype.
you can't this, because element in list dummytype. thankfully compiler saved early.
Comments
Post a Comment