[Mono-bugs] [Bug 517415] New: IEnumerator<T>.Current for List<T> Throws InvalidOperationException After MoveNext() returns false
bugzilla_noreply at novell.com
bugzilla_noreply at novell.com
Mon Jun 29 10:54:24 EDT 2009
http://bugzilla.novell.com/show_bug.cgi?id=517415
Summary: IEnumerator<T>.Current for List<T> Throws
InvalidOperationException After MoveNext() returns
false
Classification: Mono
Product: Mono: Class Libraries
Version: 2.4.x
Platform: All
OS/Version: All
Status: NEW
Severity: Normal
Priority: P5 - None
Component: System
AssignedTo: mono-bugs at lists.ximian.com
ReportedBy: stewart at medit.fr
QAContact: mono-bugs at lists.ximian.com
Found By: ---
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.11)
Gecko/2009060215 Firefox/3.0.11
The behaviour of IEnumerator<T>.Current for List<T> differs from that of
Microsoft's .Net and MSDN.
Reproducible: Always
Steps to Reproduce:
1. Create and populate List<T> collection.
2. Access IEnumerator<T> with GetEnumerator();
3. Repeat MoveNext() until it returns false.
4. Access Current property.
Actual Results:
Unhandled Exception: System.InvalidOperationException: Operation is not valid
due to the current state of the object
at System.Collections.Generic.List`1+Enumerator[System.Object].get_Current ()
[0x00000]
at (wrapper static-rgctx-invoke)
Expected Results:
Expected the return value from Current to be "undefined". Did not expect
System.InvalidOperationException exception.
While the behaviour in Mono (2.2 and 2.4 tested) might be sensible, it differs
from that observed with Microsoft's .Net 2.0.
According to MSDN, http://msdn.microsoft.com/en-us/library/58e146b7.aspx (see
Remarks section within) Current is undefined if the last call to MoveNext()
returned false. In practise, on .Net 2.0 at least, the appropriate type's
default value is returned.
A pair of NUnit test cases are given below. One demonstrates that Current
throws an exception on Mono, and the other demonstrates that the default value
for the underlying collection's type is returned.
using System;
using System.Collections.Generic;
using NUnit.Framework;
namespace Fr.Medit.Tests
{
/// <summary>
/// Test for differences between Mono and MS .Net.
/// </summary>
[TestFixture]
public class MonoVersusDotNet
{
/// <summary>
/// Tests the List{T}.Enumerator{T}.Current behaviour
/// </summary>
/// <remarks>
/// This passes on Mono 2.2 and 2.4, but fails on .Net 2.0
/// </remarks>
[Test]
public void
TestGenericListEnumeratorCurrentThrowsInvalidOperationExceptionOnMono()
{
List<int> myList = new List<int>();
myList.Add(99);
IEnumerator<int> enumerator = myList.GetEnumerator();
while (enumerator.MoveNext())
{
Assert.AreEqual(99, enumerator.Current);
}
AssertExceptionIsInvalidOperationException(delegate() { int current =
enumerator.Current; });
}
/// <summary>
/// Define a void, parameterless delegate
/// </summary>
public delegate void MethodInvoker();
/// <summary>
/// Asserts that the exception thrown is an InvalidOperationException.
/// </summary>
/// <param name="method">The method to test.</param>
public static void AssertExceptionIsInvalidOperationException(MethodInvoker
method)
{
try
{
method.DynamicInvoke(null);
Assert.Fail("Did not throw an exception");
}
catch (AssertionException ae)
{
throw ae;
}
catch (InvalidOperationException ae)
{
return;
}
catch (Exception ae)
{
throw new AssertionException("Did not throw an exception of expected
type");
}
}
/// <summary>
/// Tests the List{T}.Enumerator{T}.Current behaviour
/// </summary>
/// <remarks>
/// This passes on .Net 2.0, but fails on Mono 2.2 and 2.4
/// </remarks>
[Test]
public void TestGenericListEnumeratorCurrentReturnsDefaultOnDotNet()
{
List<int> myList = new List<int>();
myList.Add(99);
IEnumerator<int> enumerator = myList.GetEnumerator();
while (enumerator.MoveNext())
{
Assert.AreEqual(99, enumerator.Current);
}
Assert.AreEqual(default(int), enumerator.Current);
}
}
}
I propose the following patch to fix the behaviour in Mono. At
mcs/class/corlib/System.Collections.Generic/List.cs:
Replace this:
public T Current {
get {
if (idx < 0)
throw new
InvalidOperationException ();
return l.data [l.size - 1 - idx];
}
}
With this:
public T Current {
get {
return (idx < 0) ? default (T) : l.data
[l.size - 1 - idx];
}
}
--
Configure bugmail: http://bugzilla.novell.com/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.
You are the assignee for the bug.
More information about the mono-bugs
mailing list