Подтвердить что ты не робот

С# (.NET) Недостатки дизайна

Каковы некоторые из самых больших недостатков дизайна на С# или .NET Framework в целом?

Пример: нет типа нулевой строки, и вы должны проверить DBNull при извлечении значений из IDataReader.

4b9b3361

Ответ 1

Я категорически согласен с этим постом (для тех, кто пытается обойтись без ToString, есть атрибут отладчика, обеспечивающий пользовательский формат для вашего класса).

Вверху приведенного выше списка я бы также добавил следующие разумные запросы:

  1. необнуляемые ссылочные типы как дополнение к обнуляемым типам значений,
  2. разрешить переопределение структурного пустого конструктора,
  3. разрешить ограничения универсального типа указывать закрытые классы,
  4. Я согласен с другим постером, который запрашивал сигнатуры произвольного конструктора при использовании в качестве ограничений, т.е. где T : new(string) или где T : new(string, int)
  5. Я также согласен с другим постером здесь об исправлении событий, как для пустых списков событий, так и для одновременной настройки (хотя последняя сложна),
  6. операторы должны быть определены как методы расширения, а не как статические методы класса (или не только как статические методы по крайней мере),
  7. разрешить статические свойства и методы для интерфейсов (в Java это есть, а в С# нет),
  8. разрешить инициализацию события в инициализаторах объекта (в настоящее время разрешены только поля и свойства),
  9. почему синтаксис "инициализатора объекта" можно использовать только при создании объекта? Почему бы не сделать его доступным в любое время, т.е. var e = new Foo(); e { Bar = baz };
  10. исправить перечислимое квадратичное поведение,
  11. все коллекции должны иметь неизменные снимки для итерации (т.е. изменение коллекции не должно делать недействительным итератор),
  12. Кортежи легко добавить, но эффективный замкнутый алгебраический тип, такой как "Either<T>", нет, поэтому я хотел бы каким-то образом объявить замкнутый алгебраический тип и применить к нему исчерпывающее сопоставление с образцом (в основном первоклассная поддержка для посетителя). шаблон, но гораздо эффективнее); так что просто берите перечисления, расширяйте их с помощью полной поддержки сопоставления с образцом и не допускайте недопустимых случаев,
  13. Мне бы очень хотелось, чтобы поддержка сопоставления с образцом в целом, но, по крайней мере, для тестирования типов объектов; Мне также нравится синтаксис переключения, предложенный в другом посте здесь,
  14. Я согласен с другим постом, что классы System.IO, такие как Stream, несколько плохо спроектированы; любой интерфейс, который требует некоторых реализаций для выброса NotSupportedException, плохой дизайн,
  15. IList должно быть намного проще, чем есть; на самом деле, это может быть верно для многих конкретных интерфейсов сбора, таких как ICollection,
  16. слишком много методов генерируют исключения, например, IDictionary,
  17. Я бы предпочел форму проверяемых исключений лучше, чем в Java (см. исследование систем типов и эффектов, как это можно сделать),
  18. исправление различных раздражающих angular случаев в разрешении перегрузки универсального метода; например, попробуйте предоставить два перегруженных метода расширения, один из которых работает со ссылочными типами, а другой - со структурными типами, допускающими обнуляемость, и посмотрите, как это делает вывод типа
  19. обеспечить способ безопасного отражения имен полей и элементов для интерфейсов, подобных INotifyPropertyChanged, которые принимают имя поля в виде строки; Вы можете сделать это, используя метод расширения, который принимает лямбда с MemberExpression, т.е. () => Foo, но это не очень эффективно,
    • Обновление: в С# 6.0 добавлен оператор nameof() для имен отдельных членов, но он не работает в обобщенных выражениях (nameof(T) == "T" вместо действительного имени аргумента типа: вам все еще нужно сделать typeof(T).Name)) - и при этом он не позволяет вам получить строку "путь", например, nameof(this.ComplexProperty.Value) == "Value" ограничение его возможных применений.
  20. разрешить использование операторов в интерфейсах и реализовать все типы базовых номеров IArithmetic; возможны и другие полезные интерфейсы общих операторов,
  21. усложнить изменение полей/свойств объекта или, по крайней мере, разрешить аннотировать неизменяемые поля и заставить средство проверки типов применять его (просто относиться к нему только как к получателю, только если это не так сложно!); на самом деле, объединяйте поля и свойства более разумным способом, поскольку нет смысла иметь оба; Автоматические свойства С# 3.0 - это первый шаг в этом направлении, но они не заходят достаточно далеко,
    • Обновление: в то время как в С# было ключевое слово readonly, а в С# 6.0 добавлены авто-свойства только для чтения, хотя он не такой строгий, как поддержка истинного языка для неизменяемых типов и значений.
  22. упростить объявление конструкторов; Мне нравится подход F #, но другой пост, который требует просто "новый" вместо имени класса, лучше, по крайней мере,

Этого достаточно на данный момент, я полагаю. Это все раздражения, с которыми я столкнулся на прошлой неделе. Я мог бы, вероятно, продолжать часами, если бы действительно думал об этом. С# 4.0 уже добавляет именованные, необязательные и стандартные параметры, которые я категорически одобряю.

Теперь для одного необоснованного запроса:

  1. было бы действительно, очень хорошо, если бы С#/CLR мог поддерживать полиморфизм конструктора типов, т.е. дженерики над дженериками,

Довольно пожалуйста? :-)

Ответ 2

  • метод Reset() в IEnumerator<T> был ошибкой (для блоков итераторов языковая спецификация даже требует, чтобы это вызывало исключение)
  • методы отражения, которые возвращают массивы, были, по мнению Эрика, ошибкой
  • ковариация массива была и остается странностью
    • Обновление: С# 4.0 с .NET 4.0 добавлена ковариантная/контравариантная поддержка к универсальным интерфейсам (например, IEnumerable<out T> и Func<in T, out TResult>, но не к конкретным типам (например, List<T>).
  • ApplicationException скорее потерял самообладание - это было ошибкой?
  • синхронизированные коллекции - хорошая идея, но не обязательно полезная в реальности: обычно вам нужно синхронизировать несколько операций (Contains, затем Add), поэтому коллекция, которая синхронизирует отдельные операции, не так уж полезна
    • Обновление: Типы System.Collections.Concurrent с TryAdd, GetOrAdd, TryRemove и т.д. Были добавлены в .NET Framework 4.0 - хотя методы, принимающие делегат фабрики, не гарантируют, что фабрика будет работать только вызываться один раз для каждого ключа.
  • можно было бы больше использовать шаблон using/lock - возможно, позволяя им использовать повторно используемый (расширяемый?) синтаксис; Вы можете смоделировать это, возвращая IDisposable и используя using, но это могло бы быть более понятным
  • блоки итераторов: нет простого способа проверки аргументов заранее (а не лениво). Конечно, вы можете написать два цепных метода, но это уродливо
  • была бы хороша более простая неизменность; С# 4.0 помогает немного, но не достаточно
  • поддержка "этот параметр ref-type не может быть нулевой" - хотя контракты (в 4.0) несколько помогают в этом. Но синтаксис, подобный Foo(SqlConnection! connection) (который вводит нулевую проверку /throw), был бы хорош (в отличие от int? и т.д.)
  • отсутствие поддержки операторов и конструкторов не по умолчанию с обобщениями; С# 4.0 решает это немного с помощью dynamic, или вы можете включить его следующим образом
  • переменная итератора объявляется вне while в расширении foreach, что означает, что anon-method/lambdas захватывает одну переменную, а не одну за итерацию (болезненно с threading/async/etc)

Ответ 3

TextWriter - это базовый класс StreamWriter. WTF?

Это всегда смущает меня до крайности.

Ответ 4

В небольших конструкторах С# pet peev используются синтаксис С++/Java с тем, чтобы конструктор был тем же именем, что и класс.

New() или ctor() было бы намного приятнее.

И конечно, такие инструменты, как coderush, делают это менее проблемой для переименования классов, но из читаемости POV, New() обеспечивает большую ясность.

Ответ 5

Я не понимаю, что вы не можете сделать

где T: new (U)

Итак, вы заявляете, что общий тип T имеет конструктор, отличный от стандартного.

изменить

Я хочу сделать это:

public class A 
{
    public A(string text) 
    {

    }
}


public class Gen<T> where T : new(string text) 
{

}

Ответ 6

  • Я не большой поклонник Stream, StringWriter, StringReader, TextReader, классов TextWriter... это просто не интуитивно понятно, что есть.
  • IEnumerable.Reset выдает исключение для итераторов. У меня есть сторонние компоненты, которые всегда вызывают reset при привязке к базе данных, сначала мне нужно использовать список для использования.
  • Xml Сериализатор должен иметь сериализованные элементы IDictionary.
  • Я полностью забыл о HttpWebRequest и FTP API, что боль в моем.... (спасибо за комментарий Николас, чтобы напомнить мне об этом:-)

Изменить
 5. Еще одно мое раздражение - это то, как System.Reflection.BindingFlags имеет разные применения в зависимости от метода, используемого вами. В FindFields, например, что означает CreateInstance или SetField? Это случай, когда они перегружают значение этого перечисления, которое запутывает.

Ответ 7

Я очень удивлен, что я первый, кто упомянул об этом:

Наборы данных ADO.NET не отображают столбцы с нулевым значением как свойства типов с нулевым значением. Вы должны иметь возможность написать это:

int? i = myRec.Field;
myRec.Field = null;

Вместо этого вы должны написать это, что просто глупо:

int? i = (int?)myRec.IsFieldNull() ? (int?)null : myRec.Field;
myRec.SetFieldNull();

Это было раздражающим в .NET 2.0, и теперь стало еще более неприятно, что вам нужно использовать jiggery-pokery, как указано выше, в ваших хороших опрятных запросах LINQ.

Это также раздражает, что сгенерированный метод Add<TableName>Row также нечувствителен к понятию типов с нулевым значением. Тем более что сгенерированные методы TableAdapter не являются.

В .NET не так много, что заставляет меня чувствовать, что команда разработчиков сказала: "Ладно, мальчики, мы достаточно близко, отправляем!" Но это точно.

Ответ 8

Я не знаю, что я бы сказал, что это ошибка дизайна, но было бы очень приятно, если бы вы могли вывести выражение лямбда так же, как вы можете в VB:

VB:

Dim a = Function(x) x * (x - 1)

С#

Было бы неплохо, если бы это можно было сделать:

var a = x => x * (x - 1);

Вместо этого:

Func<int, int> a = x => x * (x - 1);

Я понимаю это не намного дольше, но в Code Golf каждый персонаж считается чертовски! Разве они не учитывают это при разработке этих языков программирования?:)

Ответ 9

  • System.Object класс:

    • Equals и GetHashCode - не все классы сопоставимы или хешируются, их следует перенести в интерфейс. IEwatable или IComparable (или подобное) приходит на ум.

    • ToString - не все классы могут быть преобразованы в строку, должны быть перемещены в интерфейс. IFormattable (или подобное) приходит на ум.

  • ICollection.SyncRoot свойство:

    • Продвигает плохой дизайн, внешний замок почти всегда более полезен.
  • В начале должны существовать общие функции:

    • В пространстве имен System.Collections содержится много более или менее устаревших классов и интерфейсов.

Ответ 10

Одна из вещей, которая меня раздражает, - парадокс Predicate<T> != Func<T, bool>. Они оба являются делегатами типа T -> bool, и все же они не совместимы с назначением.

Ответ 11

Некоторые люди (ISV) хотят, чтобы вы могли скомпилировать его для машинного кода во время сборки и связать его, чтобы создать собственный исполняемый файл, который не требует времени выполнения dotNet.

Ответ 12

Мне не нравится оператор С# switch.

Мне хотелось бы что-то вроде этого

switch (a) {
  1    : do_something;
  2    : do_something_else;
  3,4  : do_something_different;
  else : do_something_weird; 
}

Таким образом, больше нет разрывов (легко забыть) и возможность запятой - разделять разные значения.

Ответ 13

Мы так много знаем о методах right OO. Развязка, программирование по контракту, исключение ненадлежащего наследования, правильное использование исключений, открытый/закрытый принцип, замещаемость Лискова и т.д. Тем не менее, инфраструктура .NET не использует лучшие практики.

Для меня самый большой недостаток в дизайне .Net не стоит на плечах гигантов; продвигает менее идеальные парадигмы программирования в массы программистов, которые используют свои рамки.

Если бы MS обратила на это внимание, мир программного обеспечения мог бы сделать большие скачки в плане качества, стабильности и масштабируемости в этом десятилетии, но, увы, он, похоже, регрессирует.

Ответ 14

События на С#, где вы должны явно проверить слушателей. Разве это не было связано с событиями, чтобы транслировать, кто бы там ни был? Даже если их нет?

Ответ 15

Ужасный (и совершенно невидимый для большинства людей) O (N ^ 2) поведение вложенных/рекурсивных iterators.

Я очень потрошен, что они знают об этом, знаю как его исправить, но он не рассматривается как имеющий достаточный приоритет, чтобы заслужить включение.

Я все время работаю с подобными дереву структурами и должен исправлять иначе умный код людей, когда они непреднамеренно вводят дорогостоящие операции таким образом.

Красота "yield foreach" заключается в том, что более простой и простой синтаксис способствует правильному, результативному коду. Это "успех" что я думаю, что они должны стремиться, прежде чем добавлять новые функции для долгосрочного успеха платформы.

Ответ 16

Некоторые классы реализуют интерфейсы, но не реализуют многие из методов этого интерфейса, например, Array реализует IList, но 4 из 9 методов бросают NotSupportedException http://msdn.microsoft.com/en-us/library/system.array_members.aspx

Ответ 17

Статические элементы и вложенные типы в интерфейсах.

Это особенно полезно, когда член интерфейса имеет параметр типа, специфичного для интерфейса (например, enum). Было бы неплохо вложить тип перечисления в тип интерфейса.

Ответ 18

Жестко опасный по умолчанию характер событий. Тот факт, что вы можете вызывать событие и находиться в противоречивом состоянии из-за удаления подписчиков, просто ужасен. См. и

Ответ 19

  • null.

  • const нигде.

  • API несовместимы, например. мутация массива возвращает void, но добавление к StringBuffer возвращает тот же изменчивый StringBuffer.

  • Интерфейсы коллекции несовместимы с неизменяемыми структурами данных, например. Add в System.Collections.Generic.IList<_> не может вернуть результат.

  • Нет структурной типизации, поэтому вы пишете System.Windows.Media.Effects.SamplingMode.Bilinear вместо просто Bilinear.

  • Mutable IEnumerator интерфейс, реализованный классами, когда он должен быть неизменным struct.

  • Равенство и сравнение беспорядок: у вас есть System.IComparable и Equals, но вы также получили System.IComparable<_>, System.IEquatable, System.Collections.IComparer, System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.Collections.Generic.IComparer и System.Collections.Generic.IEqualityComparer.

  • Кортежи должны быть структурами, но структуры без необходимости блокируют устранение хвостового вызова, поэтому один из наиболее распространенных и фундаментальных типов данных будет излишне распределять и уничтожать масштабируемые parallelism.

Ответ 20

0 moonlighting as enum

особенности перечисления: http://blogs.msdn.com/abhinaba/archive/2007/01/09/more-peculiarites-of-enum.aspx

как показано на этом хорошем примере: http://plus.kaist.ac.kr/~shoh/postgresql/Npgsql/apidocs/Npgsql.NpgsqlParameterCollection.Add_overload_3.html

мое предложение, положите знак "@" на хорошее использование:

вместо:

if ((myVar и MyEnumName.ColorRed)!= 0)

используйте это:

if ((myVar и MyEnumName.ColorRed)!= @0)

Ответ 21

Чтобы добавить к длинному списку хороших точек, сделанных другими:

  • DateTime.Now == DateTime.Now в большинстве, но не во всех случаях.

  • String, который является неизменным, имеет множество вариантов построения и манипуляции, но StringBuilder (который изменен) не работает.

  • Monitor.Enter и Monitor.Exit должны были быть методами экземпляра, поэтому вместо того, чтобы вводить определенный объект для блокировки, вы можете создать новый Monitor и заблокировать его.

  • Деструкторы никогда не должны были называться деструкторами. Спецификация ECMA называет их финализаторами, что гораздо менее запутанно для толпы С++, но спецификация языка по-прежнему относится к ним как к деструкторам.

Ответ 22

То, как мы используем свойства, иногда раздражает меня. Мне нравится думать о них как о эквиваленте методов Java getFoo() и setFoo(). Но это не так.

Если Правила использования свойств указывают, что свойства должны быть установлены в любом порядке, чтобы сериализация могла работать, тогда они бесполезны для проверки времени установки. Если вы пришли из фона, где вам нравится препятствовать тому, чтобы объект позволял себе когда-либо попасть в недопустимое состояние, свойства не являются вашим решением. Иногда я не вижу, насколько они лучше, чем публичные участники, поскольку мы настолько ограничены в том, что мы должны делать в свойствах.

С этой целью я всегда желал (в основном, здесь вслух, я просто хотел бы сделать что-то подобное), чтобы каким-то образом расширить синтаксис свойств. Представьте себе что-то вроде этого:


private string password;

public string Password
{
    // Called when being set by a deserializer or a persistence
    // framework
    deserialize
    {
       // I could put some backward-compat hacks in here. Like
       // weak passwords are grandfathered in without blowing up
       this.password = value;
    }
    get
    {
       if (Thread.CurrentPrincipal.IsInRole("Administrator"))
       {
           return this.password;
       }
       else
       {
           throw new PermissionException();
       }
    }
    set
    {
       if (MeetsPasswordRequirements(value))
       {
           throw new BlahException();
       }
       this.password = value;
    }
    serialize
    {
        return this.password;
    }
}

Я не уверен, будет ли это полезно или как он будет обращаться к ним. Но я просто хочу, чтобы я мог делать больше со свойствами и действительно относился к ним как к методам get и set.

Ответ 23

Удлинительные методы хороши, но они являются уродливым способом решения проблем, которые могли быть решены с помощью чистых реальных миксов (посмотрите на рубин, чтобы увидеть, о чем я говорю), по теме mixins. Действительно хороший способ добавить их к языку - это разрешить использование дженериков для наследования. Это позволяет расширить существующие классы с помощью объектно-ориентированного подхода:

public class MyMixin<T> : T
{
    // etc...
}

это можно использовать, например, для расширения строки, например:

var newMixin = new MyMixin<string>();

Это гораздо более мощное средство, чем методы расширения, поскольку оно позволяет вам переопределять методы, например, чтобы обернуть их, что позволяет AOP-подобным функциям внутри языка.

Извините за разговор: -)

Ответ 24

Метод .Parameters.Add() в SqlCommand в V1 структуры был ужасно разработан - одна из перегрузок в основном не работала бы, если бы вы передали параметр со значением (int) 0 - это привело для них создается метод .Parameters.AddWithValue() в классе SqlCommand.

Ответ 25

  • Возможность вызова расширения метод по переменной null возможен например.

    объект a = null; a.MyExtMethod();//это вызываемое, предположим, что где-то он определил MyExtMethod

    Это может быть удобно, но он неоднозначен в вопросах исключения ссылочных ссылок.

  • Один из названий "недостаток". "C" "конфигурации" в System.configuration.dll следует заглавными буквами.

  • Обработка исключений. Исключение должно быть принудительно поймано или выброшено, как в Java, компилятор должен проверить его во время компиляции. Пользователи не должны полагаться на комментарии для информации об исключениях в целевом вызове.

Ответ 26

Microsoft не будет исправлять очевидные ошибки в структуре и не будет предоставлять перехваты, чтобы конечные пользователи могли их исправить.

Кроме того, нет возможности для исполняемых файлов на двоичном патче .NET во время выполнения и никоим образом не указывать частные версии библиотек .NET Framework без двоичного исправления собственных библиотек (для перехвата вызова загрузки), а ILDASM не распространяется, поэтому Я все равно не могу автоматизировать патч.

Ответ 27

  • Нет подмножеств ICollection<T> и IList<T>; как минимум, ковариантный интерфейс для чтения только IListSource<out T> (с перечислителем, индексом и Count) был бы чрезвычайно полезен.
  • .NET не поддерживает слабых делегатов. Обходные пути в лучшем случае неудобны, и обходные пути на стороне слушателя невозможны в частичном доверии (требуется ReflectionPermission).
  • Унифицированная унификация интерфейса запрещена, даже если это имеет смысл и не вызывает проблем.
  • В отличие от С++, типы ковариационных возвратов не разрешены в .NET
  • Невозможно поразрядное сравнение двух типов значений для равенства. В функциональной структуре persistent я писал функцию Transform(Sequence<T>, Func<T,T>), которая должна была быстро определить, возвращает ли функция тот же значение или другое значение. Если функция не изменяет большинство/всех своих аргументов, то последовательность вывода может совместно использовать некоторую/всю память из входной последовательности. Без возможности побитового сравнения любого значения типа T следует использовать гораздо более медленное сравнение, которое сильно ухудшает производительность.
  • .NET, похоже, не способен поддерживать ad-hoc-интерфейсы (например, предлагаемые в Go или Rust). Такие интерфейсы позволили бы сделать List<T> гипотетическим IListSource<U> (где T: U), даже если класс явно не реализует этот интерфейс. Есть, по крайней мере, три разные библиотеки (написано самостоятельно) для обеспечения этой функциональности (с недостатками производительности, конечно - если бы было возможно прекрасное обходное решение, было бы несправедливо называть это недостаток в .NET).
  • Другие проблемы с производительностью: IEnumerator требует двух вызовов интерфейса на итерацию. Обычные указатели меток (открытые делегаты IntPtr) или делегаты с вводом значений (IntPtr * 2) невозможны. Матрицы фиксированного размера (произвольного типа T) не могут быть встроены в классы. Нет WeakReference<T> (вы можете легко написать свой собственный, но он будет использовать броски внутри.)
  • Тот факт, что идентичные типы делегатов считаются несовместимыми (без имплицитного преобразования), в некоторых случаях был неприятным для меня (например, Predicate<T> vs Func<T,bool>). Я часто хотел бы, чтобы структурная типизация для интерфейсов и делегатов, чтобы добиться более слабой связи между компонентами, потому что в .NET этого недостаточно для классов в независимых DLL для реализации того же интерфейса - они также должны совместно использовать общую ссылку на третью DLL, которая определяет интерфейс.
  • DBNull.Value существует, хотя null одинаково хорошо служил бы той же цели.
  • С# не имеет оператора = =; вы должны написать variable = variable ?? value. Действительно, в С# есть несколько мест, которые не нуждаются в симметрии. Например, вы можете написать if (x) y(); else z(); (без фигурных скобок), но вы не можете написать try y(); finally z();.
  • При создании потока невозможно заставить дочерний поток наследовать локальные значения потока из родительского потока. BCL не только не поддерживает это, но вы не можете реализовать его самостоятельно, если вы не создадите все потоки вручную; даже если было событие создания потоков,.NET не может сказать вам "родителей" или "детей" данного потока.
  • Тот факт, что существуют два разных атрибута длины для разных типов данных: "Длина" и "граф", является незначительной неприятностью.
  • Я мог бы продолжать и продолжать бесконечно плохой дизайн WPF... и WCF (хотя и весьма полезный для некоторых сценариев) также полный бородавок. В целом, раздутость, неинтуитивность и ограниченная документация многих новых библиотек BCL заставляют меня неохотно использовать их. Многие из новых материалов могли быть намного проще, меньше, проще в использовании и понимании, более свободно связаны, лучше документированы, применимы к большему количеству случаев использования, быстрее и/или более строго типизированы.
  • Меня часто укушают ненужные связи между getterter и seters: в ​​производном или производном интерфейсе вы не можете просто добавить setter, когда базовый класс или базовый интерфейс имеет только getter; если вы переопределите геттер, тогда вам не разрешается определять сеттер; и вы не можете определить сеттер как виртуальный, но getter как не виртуальный.

Ответ 28

Одна вещь, которая меня отключила в 1.x, заключалась в использовании System.Xml.XmlValidatingReader, ValidationEventHandler ValidationEventArgs не отображала базовую XmlSchemaException (помеченную внутреннюю), которая имеет всю полезную информацию, такую ​​как linenumber и position. Вместо этого вы должны проанализировать это из свойства строки Message или использовать отражение, чтобы выкапывать его. Не так хорошо, когда вы хотите вернуть более дезинфицированную ошибку конечному пользователю.

Ответ 29

Не нравится, что вы не можете использовать значения одного перечисления в другом перечислении, например:

    enum Colors { white, blue, green, red, black, yellow }

    enum SpecialColors { Colors.blue, Colors.red, Colors.Yellow } 

Ответ 30

Неявно Типизированные переменные были реализованы слабо ИМО. Я знаю, что вы действительно должны использовать их только при работе с выражениями Linq, но это раздражает, что вы не можете объявлять их за пределами локальной области.

Из MSDN:

  • var может использоваться только тогда, когда локальная переменная объявляется и инициализируется в том же самом выражении; переменная не может быть инициализирована нулем, или группе методов или анонимной функции.
  • var не может использоваться в полях в классе.
  • Переменные, объявленные с помощью var, не могут использоваться в выражении инициализации. Другими словами, это выражение является законным: int я = (i = 20); но это выражение создает ошибку времени компиляции: var я = (i = 20);
  • Несколько неявно типизированных переменных не могут быть инициализированы в том же самом выражении.
  • Если тип с именем var находится в области видимости, ключевое слово var будет разрешено для этого имени типа и не будет рассматриваться как часть неявно типизированного объявления локальной переменной.

Причина, по которой я думаю, что это плохая реализация, заключается в том, что они называют это var, но это далеко не вариант. Это действительно просто сокращенный синтаксис для того, чтобы не вводить полное имя класса (кроме случаев, когда оно используется с Linq)