var关键字并不总是有效?

l33*_*33t 11 c# var propertydescriptor

C#,VS 2010.有人,请解释为什么我不能var在下面的代码中使用!

var props = TypeDescriptor.GetProperties(adapter);

// error CS1061: 'object' does not contain a definition for 'DisplayName'
foreach (var prop in props)
{
    string name = prop.DisplayName;
}

// No error
foreach (PropertyDescriptor prop in props)
{
    string name = prop.DisplayName;
}
Run Code Online (Sandbox Code Playgroud)

TypeDescriptor.GetProperties返回PropertyDescriptorCollection带有实例的PropertyDescriptor.为什么编译器看不到这个?

Dan*_*rth 23

TypeDescriptor.GetProperties返回一个只有一个GetEnumerator返回非泛型的实现的类IEnumerator.它的Current属性类型是object- 这是编译器可以推断的唯一类型,因此这是您的prop变量的类型.

第二foreach,使用PropertyDescriptor的而不是var作为对类型prop实际上执行从一个转换objectPropertyDescriptor.

假设这段代码:

PropertyDescriptor x = // get from somewhere;
object o = x;
PropertyDescriptor y = (PropertyDescriptor)o;
Run Code Online (Sandbox Code Playgroud)

foreach每个项目的第二个循环都会发生同样的情况.


您可以添加一个Cast<PropertyDescriptor>()以获得具有该返回IEnumerable<T>实现的泛型.如果你这样做,你可以在循环中使用:GetEnumeratorIEnumerator<T>varforeach

var props = TypeDescriptor.GetProperties(adapter).Cast<PropertyDescriptor>();

// No error
foreach (var prop in props)
{
    string name = prop.DisplayName;
}
Run Code Online (Sandbox Code Playgroud)

  • 非常迂腐,在编译器甚至关心`IEnumerable`和`IEnumareble <T>`之前,它检查是否存在公共实例方法`GetEnumerator()`,如果该方法可行(返回类型必须有一些特定的成员).这就是这种情况.实际上它是公共方法的返回类型,它使`var`表示`object`,并且不考虑接口.(编写一个只实现非泛型`IEnumerable`(显式接口实现)但其公共`GetEnumerator()`方法返回类型安全的类的类很容易.) (3认同)

Lee*_*Lee 8

PropertyDescriptorCollection仅实现IEnumerable,因此编译器只知道其中包含的元素是类型object.在foreach循环中指定类型时,编译器将向您指定的类型插入强制转换.

您可以使用Cast<T>扩展方法IEnumerable将每个项目强制转换为给定类型:

using System.Linq;
...
IEnumerable<PropertyDescriptor> descriptors = props.Cast<PropertyDescriptor>();
Run Code Online (Sandbox Code Playgroud)


Tim*_*ter 5

由于TypeDescriptor.GetProperties回报PropertyDescriptorCollection不执行IEnumerable<PropertyDescriptor>,但只有IEnumerable.

因此,prop它只是在编译时object没有DisplayName属性的.

所以你必须在foreach:明确指定类型:

foreach (PropertyDescriptor prop in props)
{
    string name = prop.DisplayName;
}
Run Code Online (Sandbox Code Playgroud)