1

Sometimes compiler can not infer the variable type.For example if I define a string List like this:

enter image description here

Or string array List:

enter image description here

Obviously compiler infer type of the item.But if I do something like this:

 public class Foo 
    : IEnumerable
{
    List<string> _fooRecords = new List<string>();

    public IEnumerator GetEnumerator()
    {
        return _fooRecords.GetEnumerator();
    }
}

Or this:

public class Foo 
    : IEnumerable
{
    List<string> _fooRecords = new List<string>();

    public IEnumerator GetEnumerator()
    {
        foreach (var item in _fooRecords)
        {
            yield return item;
        }
    }
}

Compiler can not infer the variable type:

enter image description here

Then I thought maybe I need to implement IEnumerator interface and I did something like this:

public class FooEnumerator : IEnumerator
{
    private List<string> recordsList;
    private int index;
    private string current;
    public FooEnumerator(List<string> list)
    {
        recordsList = list;
    }

    public object Current
    {
        get { return current; }
    }

    public bool MoveNext()
    {
        if (index != recordsList.Count - 1)
        {
            current = recordsList[index];
            index++; 
            return true;
        }
        return false;
    }

    public void Reset()
    {
        index = 0;
    }
}

And use it like (in Foo Class):

public IEnumerator GetEnumerator()
{
     return new FooEnumerator(_fooRecords);
}

But nothings changed.Now I'm wondering why compiler can't infer the loop variable type for custom types? Ofcourse Foo class was just an example,there are numbers of custom collections in .NET Framework.For example ControlCollection of Form Class:

When I loop through Form control's I can't do this:

foreach (var item in this.Controls)
{
     item.Name = "bla bla bla.."; //error
}

I need to specify the type or I need to use OfType extension method:

foreach (Control item in this.Controls)
{
     item.Name = "bla bla bla.."; // OK!
}

foreach (var item in this.Controls.OfType<Control>())
{
     item.Name = "bla bla bla.."; // OK!
}

Now I'm just wondering what is the actual reason,compiler isn't smart enough? Or just can not make sure the returning type until the loop executes ?

1
  • Have you tried implementing IEnumerable<T> instead of IEnumerable? Commented Feb 1, 2014 at 10:39

4 Answers 4

4

A non-generic enumerator can return any object (the type of the Current field is object), so the compiler cannot infer anything. In a generic enumerator of type T, the element type T is inferred. Luckily the foreach construct supports specifying a type and doesn't do any compile-time verification, so non-generic enumerators can be handled easily.

Sign up to request clarification or add additional context in comments.

2 Comments

Yeah I was wondering that too, but I think there is a type verification anyway.Because returning type of current is object as you mentioned and when I do (int item in Foo) or (string item in Foo) both string and int valid for object so it doesn't give any error.
Naturally there is a verification, but it's runtime only, and throws an InvalidCastException when you give the wrong type. The only convenience here is that you don't have to do the casting yourself.
2

It infers IEnumerator. How is it possibly to know what type this iterator is iterating when IEnumerator is for iterating over objects?

Changing your GetEnumerator method in Foo to this:

public IEnumerator<string> GetEnumerator()

..allows the sort of inference you are expecting.. since IEnumerator<T> actually has type information.

1 Comment

I'm glad you understood that.. its a bit late for me. Re-reading my answer I am embarassed of it.. but I'm going to leave it in fear of making it worse at this hour of the night.
0

You need to implement IEnumerable<T> instead on / in addition to IEnumerable.

Comments

0

The compiler is not really "inferring" the type when using var, it actually looks up on the return values and then choose the right Type to use.

The problem you're facing is the use non-generic Enumerable, this is an older version of collections in C# that do not specify the type of the items inside, (Object is used always). that is why the Type being assigned to var is Object, because the return value is Object.

If you have a list that all of its items are of the same type you probably want to use IEnumerable<T> (here), for example:

public class Foo : IEnumerable<string>
{
    private readonly List<string> list;

    public Foo()
    {
        this.list = new List<string>();
    }

    /// <summary>
    /// Returns an enumerator that iterates through the collection.
    /// </summary>
    /// <returns>
    /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
    /// </returns>
    public IEnumerator<string> GetEnumerator()
    {
        return this.list.GetEnumerator();
    }

    /// <summary>
    /// Returns an enumerator that iterates through a collection.
    /// </summary>
    /// <returns>
    /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
    /// </returns>
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

2 Comments

infer - deduce or conclude (something) from evidence and reasoning rather than from explicit statements. Sounds like its inferring to me..
@SimonWhitehead well for human yes, but for the compiler everything is known so there is no "inferring" really.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.