Вопрос

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 ?

Это было полезно?

Решение

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.

Другие советы

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.

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

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();
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top