有时编译器无法推断变量类型。例如,如果我像这样定义string
列表:
或字符串数组列表:
显然编译器推断了item的类型。但是如果我这样做的话:
public class Foo
: IEnumerable
{
List<string> _fooRecords = new List<string>();
public IEnumerator GetEnumerator()
{
return _fooRecords.GetEnumerator();
}
}
或者这个:
public class Foo
: IEnumerable
{
List<string> _fooRecords = new List<string>();
public IEnumerator GetEnumerator()
{
foreach (var item in _fooRecords)
{
yield return item;
}
}
}
编译器无法推断变量类型:
然后我想也许我需要实现IEnumerator接口,我做了类似的事情:
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;
}
}
并使用它(在Foo类中):
public IEnumerator GetEnumerator()
{
return new FooEnumerator(_fooRecords);
}
但是没有改变。现在我想知道为什么编译器无法推断自定义类型的循环变量类型? Ofcourse Foo
类只是一个示例,.NET Framework中有许多自定义集合。例如ControlCollection
的{{1}}类:
当我循环使用Form控件时,我无法执行此操作:
Form
我需要指定类型或我需要使用foreach (var item in this.Controls)
{
item.Name = "bla bla bla.."; //error
}
扩展方法:
OfType
现在我只是想知道实际原因是什么,编译器不够智能?或者只是在循环执行之前无法确定返回的类型?
答案 0 :(得分:4)
non-generic enumerator可以返回任何对象(Current
字段的类型是对象),因此编译器无法推断任何内容。在类型T的generic enumerator中,推断出元素类型T.幸运的是,foreach构造支持指定类型并且不进行任何编译时验证,因此可以轻松处理非泛型枚举器。
答案 1 :(得分:2)
它推断IEnumerator
。当IEnumerator
迭代object
时,如何知道迭代器迭代的类型?
将GetEnumerator
中的Foo
方法更改为:
public IEnumerator<string> GetEnumerator()
..允许你期望的那种推理..因为IEnumerator<T>
实际上有类型信息。
答案 2 :(得分:0)
您需要在IEnumerable<T>
上添加IEnumerable
而不是{{1}}。
答案 3 :(得分:0)
编译器在使用var时并不是真正“推断”类型,它实际上会查找返回值,然后选择要使用的正确Type
。
您遇到的问题是使用非泛型Enumerable
,这是C#中旧版本的集合,未指定内部项目的类型,(Object
始终使用)。这就是分配给var
的类型为Object
的原因,因为返回值为Object
。
如果您有一个列表,其所有项目属于同一类型,您可能希望使用IEnumerable<T>
(here),例如:
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();
}
}