views:

72

answers:

2

I have two classes, GenericList and SpecificList, where SpecificList inherits from GenericList. GenericList implements IEnumerable<GenericItem> and SpecificList implements IEnumerable<SpecificItem>. SpecificItem inherits from GenericItem. I have to implement GetEnumerator in both GenericList and SpecificList since they implement IEnumerable<T>. In GenericList, it's easy enough, I just return the enumerator for the underlying List<T>:

public IEnumerator<GenericItem> GetEnumerator()
{
    return genericItemsList.GetEnumerator();
}

However, in SpecificList, it seems trickier. It seems risky to cast IEnumerator<GenericItem> to IEnumerator<SpecificItem>, and I don't know if that would even work. Instead, I did the following:

public new IEnumerator<SpecificItem> GetEnumerator()
{
    IEnumerator<GenericItem> enumerator = base.GetEnumerator();
    while (enumerator.MoveNext())
    {
        yield return (SpecificItem)enumerator.Current;
    }
}

This compiles fine and a simple MSTest unit test calling SpecificList.GetEnumerator() seems to show it works. However, ReSharper highlights base in the above method with the following warning:

Access to GenericList.GetEnumerator through 'base' keyword from anonymous method, lambda expression, query expression or iterator results in unverifiable code

Is this something I should worry about? Should I do something differently?

Edit: I'm using ReSharper 5.1 Full Edition Pre-Release Build 5.1.1715.35.

Also, I should take a break from running MSTest unit tests: I just hit Ctrl+R, Ctrl+T in Chrome to reload the page...

+4  A: 

R# is correct that accessing the base keyword inside an iterator / lambda in the 3.0 version of the C# compiler could result in unverifiable code. When it does or doesn't is a bit complex and I won't attempt to cover it here.

The easiest way to work around this is to wrap the call to base.GetEnumerator in another non-static private method and reference that from your iterator.

private IEnumerator<GenericItem> GetBaseEnumerator() {
  return base.GetEnumerator();
}

public new IEnumerator<SpecificItem> GetEnumerator()
{
    IEnumerator<GenericItem> enumerator = GetBaseEnumerator();
    while (enumerator.MoveNext())
    {
        yield return (SpecificItem)enumerator.Current;
    }
}

I'm fairly certain this bug was fixed in the 4.0 version of the C# compiler.

JaredPar
Thanks. Possibly a dumb question, but does the version of the C# compiler I'm using depend on the version of .NET I'm using? It's a .NET 3.5 project--does that guarantee me a certain version of the C# compiler?
Sarah Vessels
@Sarah, it's more tied to the version of Visual Studio you are running than the framework you are targeting. 2008 = C# 3.0 and 2010 = C# 4.0
JaredPar
@JaredPar: aha! I'm in 2008 SP1. Your suggestion removes the ReSharper warning, and all seems to work. :)
Sarah Vessels
A: 

It seems risky to cast IEnumerator<GenericItem> to IEnumerator<SpecificItem>, and I don't know if that would even work.

Sure it would.

return base.Cast<SpecificItem>().GetEnumerator();

No more or less risky than your current implementation. In fact, I'm pretty sure it's more-or-less the same code under the hood.

Anon.
That makes Visual Studio 2008 angry. `Cast` is highlighted in red and it says "Cannot resolve symbol 'Cast'".
Sarah Vessels
@Sarah - You may need to add `using System.Linq;`
ChaosPandion
@ChaosPandion: there's already a `using` directive for `System.Linq`.
Sarah Vessels