c# - Why is the error handling for IEnumerator.Current different from IEnumerator<T>.Current? -
i have thought executing following code empty collection implements ienumerable<t> throw exception:
var enumerator = collection.getenumerator(); enumerator.movenext(); var type = enumerator.current.gettype(); // surely should throw? because collection empty, accessing ienumerator.current invalid, , have expected exception. however, no exception thrown list<t>.
this allowed the documentation ienumerator<t>.current, states current undefined under of following conditions:
- the enumerator positioned before first element in collection, after enumerator created. movenext must called advance enumerator first element of collection before reading value of current.
- the last call movenext returned false, indicates end of collection.
- the enumerator invalidated due changes made in collection, such adding, modifying, or deleting elements.
(i'm assuming "fails throw exception" can categorised "undefined behaviour"...)
however, if same thing use ienumerable instead, exception. behaviour specified the documentation ienumerator.current, states:
- current should throw invalidoperationexception if last call movenext returned false, indicates end of collection.
my question is: why difference? there technical reason i'm unaware of?
it means identical-seeming code can behave differently depending on whether it's using ienumerable<t> or ienumerable, following program demonstrates (note how code inside showelementtype1() , showelementtype1() identical):
using system; using system.collections; using system.collections.generic; namespace consoleapplication2 { class program { public static void main() { var list = new list<int>(); showelementtype1(list); // not throw exception. showelementtype2(list); // throws exception. } private static void showelementtype1(ienumerable<int> collection) { var enumerator = collection.getenumerator(); enumerator.movenext(); var type = enumerator.current.gettype(); // no exception thrown here. console.writeline(type); } private static void showelementtype2(ienumerable collection) { var enumerator = collection.getenumerator(); enumerator.movenext(); var type = enumerator.current.gettype(); // invalidoperationexception thrown here. console.writeline(type); } } }
the problem ienumerable<t> current of type t. instead of throwing exception, default(t) returned (it set movenextrare).
when using ienumerable don't have type, , can't return default value.
the actual problem don't check return value of movenext. if returns false, shouldn't call current. exception okay. think found more convenient return default(t) in ienumerable<t> case.
exception handling brings overhead, returning default(t) doesn't (that much). maybe thought there nothing useful return current property in case of ienumerable (they don't know type). problem 'solved' in ienumerable<t> when using default(t).
according bug report (thanks jesse commenting):
for performance reasons current property of generated enumerators kept extremely simple - returns value of generated 'current' backing field.
this point in direction of overhead of exception handling. or required step validate value of current.
they wave responsibility foreach, since main user of enumerator:
the vast majority of interactions enumerators in form of foreach loops guard against accessing current in either of these states wasteful burn cpu cycles every iteration check these states no 1 ever encounter.
Comments
Post a Comment