Набрав следующий фрагмент кода, я заметил, что Intellisense не работает должным образом:
StringBuilder sb = new StringBuilder();
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(sb))
{
var name = prop.DisplayName;
Console.WriteLine("{0}", name);
}
В предложении foreach, если я начну печатать prop.Di, Intellisense завершится как expexcted с prop.DisplayName. Однако я использую ключевое слово var вместо PropertyDescriptor
, тогда я вижу только метод, унаследованный от объекта.
Поскольку TypeDescriptor.GetProperties()
возвращает коллекцию TypeDescriptor, я думал, что Visual Studio сможет вывести правильный тип для prop
.
Почему это не работает?
GetProperties
возвращает PropertyDescriptorCollection
который реализует только IEnumerable
, а не IEnumerable<PropertyDescriptor>
. Если вы используете var
, тип prop
определяется как object
не PropertyDescriptor
.
Он возвращает PropertyDescriptorCollection
, а возвращаемый тип метода GetEnumerator
PropertyDescriptorCollection
- IEnumerator
(не общий). Так что даже вы можете написать
foreach (int prop in TypeDescriptor.GetProperties(sb))
И вы не получите никаких исключений во время компиляции, но во время выполнения вы получите InvalidCastException
.
Вот пример, демонстрирующий разницу:
Обычно это недопустимо:
foreach(string x in new List<int>())
Поскольку List<T>
реализует IEnumerable<T>
Но если вы оберните его классом и реализуете не общий интерфейс IEnumerable
:
class NonGenericCollection : IEnumerable
{
public List<int> List { get; set; }
public NonGenericCollection()
{
List = new List<int>();
}
public IEnumerator GetEnumerator()
{
return List.GetEnumerator();
}
}
Вы можете написать любой тип, который вы хотите, и не получать никаких исключений во время компиляции:
foreach(string x in new NonGenericCollection())
Поскольку тип возвращаемого значения выводится как объект, а фактический тип неизвестен до времени выполнения.
foreach(string x in new List<int>())
недопустима, потому что нет преобразования типа int в строку, а не потому, чтоList<T>
реализуетIEnumerable<T>
. ИзменитеList<int>
наList<object>
и у компилятора нет возражений.