[{"data":1,"prerenderedAt":759},["ShallowReactive",2],{"blog:2006:ienumerable_t_to_ienumerable_subclassoft":3,"blogMore-Development":745,"comments-ienumerable_t_to_ienumerable_subclassoft":758},{"id":4,"title":5,"body":6,"category":728,"commentCount":351,"date":729,"description":730,"excerpt":731,"extension":732,"filenames":733,"hidden":734,"image":733,"meta":735,"minutes":164,"navigation":234,"path":736,"seo":737,"showCategory":733,"stem":738,"tags":739,"updated":733,"url":742,"wordCount":743,"__hash__":744},"content\u002Fblog\u002F2006\u002Fienumerable_t_to_ienumerable_subclassoft.md","IEnumerable\u003CT> as IEnumerable\u003CBaseClassOfT>",{"type":7,"value":8,"toc":726},"minimark",[9,25,44,73,82,92,98,101,168,178,181,714,717,722],[10,11,12,13,17,18,21,22,24],"p",{},"A few weeks ago I touched on the substitutability of generic types and how ",[14,15,16],"code",{},"Collection\u003CBaseClass>"," is never substitutable for ",[14,19,20],{},"Collection\u003CSubClass>",". This is because while the read facilities would be substitutable the write ones would not be. A ",[14,23,20],{}," can’t contain non-SubClass classes.",[10,26,27,28,35,36,39,40,43],{},"One approach for dealing with collections in general recommended in ",[29,30,34],"a",{"href":31,"rel":32},"https:\u002F\u002Fwww.awprofessional.com\u002Fbookstore\u002Fproduct.asp?isbn=0321246756&rl=1",[33],"nofollow",".NET Framework Design Guidelines"," is to expose ",[14,37,38],{},"IEnumerator"," or ",[14,41,42],{},"IEnumerable"," interfaces rather than the collection itself, especially if you intend on it being read-only.",[10,45,46,47,50,51,54,55,58,59,61,62,66,67,69,70,72],{},"But even ",[14,48,49],{},"IEnumerator\u003CT>"," and ",[14,52,53],{},"IEnumerable\u003CT>"," can’t help you if you need to return not ",[14,56,57],{},"\u003CT>"," but a base-class or interface that ",[14,60,57],{}," should be substitutable for. Unless the base-class you want ",[63,64,65],"em",{},"is object"," in which case seeing ",[14,68,53],{}," inherits from the non-generic ",[14,71,42],{}," solves your problem.",[10,74,75,76,81],{},"C#’s generics aren’t clever enough to realize that an instantiated generic class might be substitutable for another generic class although. Wilco points out that the ",[29,77,80],{"href":78,"rel":79},"https:\u002F\u002Fblogs.msdn.com\u002Frmbyers\u002Farchive\u002F2005\u002F02\u002F16\u002F375079.aspx",[33],".NET CLR supports “generic contravariance”"," but C# doesn’t yet expose it.",[10,83,84,85,87,88,91],{},"In the mean time trying to passing back ",[14,86,49],{}," to something expecting ",[14,89,90],{},"IEnumerator\u003CBaseClassOfT>"," will result in a compiler error. Try cast ing it and a run-time error awaits.",[10,93,94,95,97],{},"One option would be to create a whole new ",[14,96,16],{}," and copy each SubClass element into it but this is hardly efficient or elegant.",[10,99,100],{},"What would be really cool is if you could somehow wrap it like;",[102,103,108],"pre",{"className":104,"code":105,"language":106,"meta":107,"style":107},"language-csharp shiki shiki-themes everforest-light dracula","public IEnumerable\u003CBaseClass> BaseClasses {\n    return new BaseEnumerable\u003CBaseClass, SubClass>(subClassCollection);\n}\n","csharp","",[14,109,110,135,162],{"__ignoreMap":107},[111,112,115,119,123,126,129,132],"span",{"class":113,"line":114},"line",1,[111,116,118],{"class":117},"s9HRq","public",[111,120,122],{"class":121},"s6Vpi"," IEnumerable",[111,124,125],{"class":117},"\u003C",[111,127,128],{"class":121},"BaseClass",[111,130,131],{"class":117},">",[111,133,134],{"class":121}," BaseClasses {\n",[111,136,138,142,145,149,151,153,156,159],{"class":113,"line":137},2,[111,139,141],{"class":140},"smiwp","    return",[111,143,144],{"class":140}," new",[111,146,148],{"class":147},"snuxY"," BaseEnumerable",[111,150,125],{"class":121},[111,152,128],{"class":147},[111,154,155],{"class":121},", ",[111,157,158],{"class":147},"SubClass",[111,160,161],{"class":121},">(subClassCollection);\n",[111,163,165],{"class":113,"line":164},3,[111,166,167],{"class":121},"}\n",[10,169,170,171,174,175,177],{},"You’d need BaseEnumerator and ",[14,172,173],{},"BaseEnumerable"," generic classes to do this and preferably they’d be able to enforce that SubClass is of ",[14,176,128],{}," at compile time.",[10,179,180],{},"So here are two classes to do just that for your enumerable pleasure.",[102,182,184],{"className":104,"code":183,"language":106,"meta":107,"style":107},"using System;\nusing System.Collections;\nusing System.Collections.Generic;\n\npublic class BaseEnumerable\u003CTBase, TSub> : IEnumerable\u003CTBase> where TSub : TBase {\n    private IEnumerable\u003CTSub> subEnumerable;\n\n    public BaseEnumerable(IEnumerable\u003CTSub> subEnumerable) {\n        this.subEnumerable = subEnumerable;\n    }\n\n    public IEnumerator\u003CTBase> GetEnumerator() {\n        return new BaseEnumerator\u003CTBase, TSub>(subEnumerable);\n    }\n\n    IEnumerator IEnumerable.GetEnumerator() {\n        return subEnumerable.GetEnumerator();\n    }\n}\n\npublic class BaseEnumerator\u003CTBase, TSub> : IEnumerable\u003CTBase> where TSub : TBase {\n    private IEnumerator\u003CTSub> subEnumerator;\n\n    public BaseEnumerator(IEnumerable\u003CTSub> subEnumerable) {\n        subEnumerator = subEnumerable.GetEnumerator();\n    }\n\n    public BaseEnumerator(IEnumerable\u003CTSub> subEnumerator) {\n        this.subEnumerator = subEnumerator;\n    }\n\n    public TBase Current {\n        get { return subEnumerator.Current; }\n    }\n\n    public bool MoveNext() {\n        return subEnumerator.MoveNext();\n    }\n\n    public void Reset() {\n        subEnumerator.Reset();\n    }\n}\n",[14,185,186,198,212,229,236,284,299,304,331,349,355,360,380,402,407,412,426,439,444,449,454,491,505,510,531,546,551,556,578,592,597,602,613,635,640,645,658,670,675,680,693,704,709],{"__ignoreMap":107},[111,187,188,191,195],{"class":113,"line":114},[111,189,190],{"class":140},"using",[111,192,194],{"class":193},"sjYfO"," System",[111,196,197],{"class":121},";\n",[111,199,200,202,204,207,210],{"class":113,"line":137},[111,201,190],{"class":140},[111,203,194],{"class":193},[111,205,206],{"class":121},".",[111,208,209],{"class":193},"Collections",[111,211,197],{"class":121},[111,213,214,216,218,220,222,224,227],{"class":113,"line":164},[111,215,190],{"class":140},[111,217,194],{"class":193},[111,219,206],{"class":121},[111,221,209],{"class":193},[111,223,206],{"class":121},[111,225,226],{"class":193},"Generic",[111,228,197],{"class":121},[111,230,232],{"class":113,"line":231},4,[111,233,235],{"emptyLinePlaceholder":234},true,"\n",[111,237,239,241,244,247,249,253,255,258,261,263,265,267,270,273,276,279,281],{"class":113,"line":238},5,[111,240,118],{"class":117},[111,242,243],{"class":140}," class",[111,245,148],{"class":246},"sPLAf",[111,248,125],{"class":121},[111,250,252],{"class":251},"sAO9U","TBase",[111,254,155],{"class":121},[111,256,257],{"class":251},"TSub",[111,259,260],{"class":121},"> : ",[111,262,42],{"class":147},[111,264,125],{"class":121},[111,266,252],{"class":147},[111,268,269],{"class":121},"> ",[111,271,272],{"class":117},"where",[111,274,275],{"class":251}," TSub",[111,277,278],{"class":121}," : ",[111,280,252],{"class":147},[111,282,283],{"class":121}," {\n",[111,285,287,290,292,294,296],{"class":113,"line":286},6,[111,288,289],{"class":117},"    private",[111,291,122],{"class":147},[111,293,125],{"class":121},[111,295,257],{"class":147},[111,297,298],{"class":121},"> subEnumerable;\n",[111,300,302],{"class":113,"line":301},7,[111,303,235],{"emptyLinePlaceholder":234},[111,305,307,310,313,316,318,320,322,324,328],{"class":113,"line":306},8,[111,308,309],{"class":117},"    public",[111,311,148],{"class":312},"sS4Kt",[111,314,315],{"class":121},"(",[111,317,42],{"class":147},[111,319,125],{"class":121},[111,321,257],{"class":147},[111,323,269],{"class":121},[111,325,327],{"class":326},"s7cAX","subEnumerable",[111,329,330],{"class":121},") {\n",[111,332,334,338,340,343,346],{"class":113,"line":333},9,[111,335,337],{"class":336},"sKO3f","        this",[111,339,206],{"class":121},[111,341,327],{"class":342},"sSKRk",[111,344,345],{"class":117}," =",[111,347,348],{"class":121}," subEnumerable;\n",[111,350,352],{"class":113,"line":351},10,[111,353,354],{"class":121},"    }\n",[111,356,358],{"class":113,"line":357},11,[111,359,235],{"emptyLinePlaceholder":234},[111,361,363,365,368,370,372,374,377],{"class":113,"line":362},12,[111,364,309],{"class":117},[111,366,367],{"class":147}," IEnumerator",[111,369,125],{"class":121},[111,371,252],{"class":147},[111,373,269],{"class":121},[111,375,376],{"class":312},"GetEnumerator",[111,378,379],{"class":121},"() {\n",[111,381,383,386,388,391,393,395,397,399],{"class":113,"line":382},13,[111,384,385],{"class":140},"        return",[111,387,144],{"class":140},[111,389,390],{"class":147}," BaseEnumerator",[111,392,125],{"class":121},[111,394,252],{"class":147},[111,396,155],{"class":121},[111,398,257],{"class":147},[111,400,401],{"class":121},">(subEnumerable);\n",[111,403,405],{"class":113,"line":404},14,[111,406,354],{"class":121},[111,408,410],{"class":113,"line":409},15,[111,411,235],{"emptyLinePlaceholder":234},[111,413,415,418,420,422,424],{"class":113,"line":414},16,[111,416,417],{"class":147},"    IEnumerator",[111,419,122],{"class":147},[111,421,206],{"class":121},[111,423,376],{"class":312},[111,425,379],{"class":121},[111,427,429,431,434,436],{"class":113,"line":428},17,[111,430,385],{"class":140},[111,432,433],{"class":121}," subEnumerable.",[111,435,376],{"class":312},[111,437,438],{"class":121},"();\n",[111,440,442],{"class":113,"line":441},18,[111,443,354],{"class":121},[111,445,447],{"class":113,"line":446},19,[111,448,167],{"class":121},[111,450,452],{"class":113,"line":451},20,[111,453,235],{"emptyLinePlaceholder":234},[111,455,457,459,461,463,465,467,469,471,473,475,477,479,481,483,485,487,489],{"class":113,"line":456},21,[111,458,118],{"class":117},[111,460,243],{"class":140},[111,462,390],{"class":246},[111,464,125],{"class":121},[111,466,252],{"class":251},[111,468,155],{"class":121},[111,470,257],{"class":251},[111,472,260],{"class":121},[111,474,42],{"class":147},[111,476,125],{"class":121},[111,478,252],{"class":147},[111,480,269],{"class":121},[111,482,272],{"class":117},[111,484,275],{"class":251},[111,486,278],{"class":121},[111,488,252],{"class":147},[111,490,283],{"class":121},[111,492,494,496,498,500,502],{"class":113,"line":493},22,[111,495,289],{"class":117},[111,497,367],{"class":147},[111,499,125],{"class":121},[111,501,257],{"class":147},[111,503,504],{"class":121},"> subEnumerator;\n",[111,506,508],{"class":113,"line":507},23,[111,509,235],{"emptyLinePlaceholder":234},[111,511,513,515,517,519,521,523,525,527,529],{"class":113,"line":512},24,[111,514,309],{"class":117},[111,516,390],{"class":312},[111,518,315],{"class":121},[111,520,42],{"class":147},[111,522,125],{"class":121},[111,524,257],{"class":147},[111,526,269],{"class":121},[111,528,327],{"class":326},[111,530,330],{"class":121},[111,532,534,537,540,542,544],{"class":113,"line":533},25,[111,535,536],{"class":121},"        subEnumerator ",[111,538,539],{"class":117},"=",[111,541,433],{"class":121},[111,543,376],{"class":312},[111,545,438],{"class":121},[111,547,549],{"class":113,"line":548},26,[111,550,354],{"class":121},[111,552,554],{"class":113,"line":553},27,[111,555,235],{"emptyLinePlaceholder":234},[111,557,559,561,563,565,567,569,571,573,576],{"class":113,"line":558},28,[111,560,309],{"class":117},[111,562,390],{"class":312},[111,564,315],{"class":121},[111,566,42],{"class":147},[111,568,125],{"class":121},[111,570,257],{"class":147},[111,572,269],{"class":121},[111,574,575],{"class":326},"subEnumerator",[111,577,330],{"class":121},[111,579,581,583,585,587,589],{"class":113,"line":580},29,[111,582,337],{"class":336},[111,584,206],{"class":121},[111,586,575],{"class":342},[111,588,345],{"class":117},[111,590,591],{"class":121}," subEnumerator;\n",[111,593,595],{"class":113,"line":594},30,[111,596,354],{"class":121},[111,598,600],{"class":113,"line":599},31,[111,601,235],{"emptyLinePlaceholder":234},[111,603,605,607,610],{"class":113,"line":604},32,[111,606,309],{"class":117},[111,608,609],{"class":147}," TBase",[111,611,612],{"class":121}," Current {\n",[111,614,616,620,623,626,629,632],{"class":113,"line":615},33,[111,617,619],{"class":618},"sXAHl","        get",[111,621,622],{"class":121}," { ",[111,624,625],{"class":140},"return",[111,627,628],{"class":121}," subEnumerator.",[111,630,631],{"class":342},"Current",[111,633,634],{"class":121},"; }\n",[111,636,638],{"class":113,"line":637},34,[111,639,354],{"class":121},[111,641,643],{"class":113,"line":642},35,[111,644,235],{"emptyLinePlaceholder":234},[111,646,648,650,653,656],{"class":113,"line":647},36,[111,649,309],{"class":117},[111,651,652],{"class":618}," bool",[111,654,655],{"class":312}," MoveNext",[111,657,379],{"class":121},[111,659,661,663,665,668],{"class":113,"line":660},37,[111,662,385],{"class":140},[111,664,628],{"class":121},[111,666,667],{"class":312},"MoveNext",[111,669,438],{"class":121},[111,671,673],{"class":113,"line":672},38,[111,674,354],{"class":121},[111,676,678],{"class":113,"line":677},39,[111,679,235],{"emptyLinePlaceholder":234},[111,681,683,685,688,691],{"class":113,"line":682},40,[111,684,309],{"class":117},[111,686,687],{"class":618}," void",[111,689,690],{"class":312}," Reset",[111,692,379],{"class":121},[111,694,696,699,702],{"class":113,"line":695},41,[111,697,698],{"class":121},"        subEnumerator.",[111,700,701],{"class":312},"Reset",[111,703,438],{"class":121},[111,705,707],{"class":113,"line":706},42,[111,708,354],{"class":121},[111,710,712],{"class":113,"line":711},43,[111,713,167],{"class":121},[10,715,716],{},"They work clean and fast for me but I’m no expert on the responsibilities of implementing the Dispose pattern. Warranty is not included and your mileage may vary.",[10,718,719],{},[63,720,721],{},"[)amien",[723,724,725],"style",{},"html pre.shiki code .s9HRq, html code.shiki .s9HRq{--shiki-default:#F57D26;--shiki-dark:#FF79C6}html pre.shiki code .s6Vpi, html code.shiki .s6Vpi{--shiki-default:#5C6A72;--shiki-dark:#F8F8F2}html pre.shiki code .smiwp, html code.shiki .smiwp{--shiki-default:#F85552;--shiki-dark:#FF79C6}html pre.shiki code .snuxY, html code.shiki .snuxY{--shiki-default:#3A94C5;--shiki-default-font-style:inherit;--shiki-dark:#8BE9FD;--shiki-dark-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sjYfO, html code.shiki .sjYfO{--shiki-default:#DF69BA;--shiki-default-font-style:inherit;--shiki-dark:#8BE9FD;--shiki-dark-font-style:italic}html pre.shiki code .sPLAf, html code.shiki .sPLAf{--shiki-default:#3A94C5;--shiki-dark:#8BE9FD}html pre.shiki code .sAO9U, html code.shiki .sAO9U{--shiki-default:#3A94C5;--shiki-default-font-style:inherit;--shiki-dark:#FFB86C;--shiki-dark-font-style:italic}html pre.shiki code .sS4Kt, html code.shiki .sS4Kt{--shiki-default:#8DA101;--shiki-dark:#50FA7B}html pre.shiki code .s7cAX, html code.shiki .s7cAX{--shiki-default:#5C6A72;--shiki-default-font-style:inherit;--shiki-dark:#FFB86C;--shiki-dark-font-style:italic}html pre.shiki code .sKO3f, html code.shiki .sKO3f{--shiki-default:#DF69BA;--shiki-default-font-style:inherit;--shiki-dark:#BD93F9;--shiki-dark-font-style:italic}html pre.shiki code .sSKRk, html code.shiki .sSKRk{--shiki-default:#35A77C;--shiki-dark:#F8F8F2}html pre.shiki code .sXAHl, html code.shiki .sXAHl{--shiki-default:#3A94C5;--shiki-dark:#FF79C6}",{"title":107,"searchDepth":137,"depth":137,"links":727},[],"Development","2006-05-24T06:39:14+00:00","A few weeks ago I touched on the substitutability of generic types and how Collection\u003CBaseClass> is never substitutable for Collection\u003CSubClass>. This is because while the read facilities would be substitutable the write ones would not be. A Collection\u003CSubClass> can’t contain non-SubClass classes.","[object Object]","md",null,false,{},"\u002Fblog\u002F2006\u002Fienumerable_t_to_ienumerable_subclassoft",{"title":5,"description":730},"blog\u002F2006\u002Fienumerable_t_to_ienumerable_subclassoft",[740,741],".NET","C#","\u002Fblog\u002F2006\u002Fienumerable_t_to_ienumerable_subclassoft\u002F",586,"-7gepTB2FrvydLUXUuOmJPWu45FFKGO_ElywPUxmjCw",[746,750,754],{"title":747,"date":748,"url":749},"Transactions in the MongoDB EF Core Provider","2025-10-25","\u002Fblog\u002F2025\u002Fmongodb-explicit-transactions\u002F",{"title":751,"date":752,"url":753},"Queryable Encryption with the MongoDB EF Core Provider","2025-09-22","\u002Fblog\u002F2025\u002Fmongodb-queryable-encryption\u002F",{"title":755,"date":756,"url":757},"Lazy Loading with EF Core Proxies","2025-04-02","\u002Fblog\u002F2025\u002Fef-proxies\u002F",[],1780900533338]