Если это относится к конкретному экземпляру, то он должен быть членом экземпляра (будь то метод, свойство или поле). Это наиболее распространенные случаи, поэтому примеров много.
Если это не относится к конкретному экземпляру, то члену экземпляра требуется экземпляр, который вы не будете использовать каким-либо другим способом.Хорошим примером является Math.Max
, если вы позвоните по номеру Math.Max(43, 23)
, тогда результат будет связан с тем фактом, что 43 больше 23, а не для какого-либо свойства объекта Math
, которое, возможно, может измениться в ходе работы приложения.
Некоторые классы нуждаются только в статических элементах, поэтому мы ставим статический класс и его нельзя создать вообще.
Протеи, которые относятся к природе класса, а не к данному экземпляру, также должны быть статическими по той же причине. Например. int.MaxValue
является собственностью int
, а не, например, 93.
Обратите внимание, что результат int.MaxValue
сам по себе является int
. Это не редкость. Другие примеры включают TimeSpan.Zero
и string.Empty
. Это может быть удобством, а иногда и полезным преимуществом в предотвращении множества повторяющихся ссылочных типов (нерелевантно в случае типов значений и не должно быть переопределено в случае ссылочных типов). Важно не делать этого. Нам не хотелось бы 4294967296 различных статических свойств на int
, чтобы их «легко» называть! Обычно это полезно, когда:
Специальный конструктор не может быть сконструирован конструктором.
ИЛИ:
Особый случай обычно используется (TimeSpan.Zero
) и/или неудобным помнить (int.MaxValue
яснее и проще вспомнить, чем 2147483647
или даже 0x7FFFFFFF
). Тем более, если это конечно.
Методы расширения - это статические методы, которые могут быть вызваны, как если бы они были членами экземпляра. Они очень удобны, но обычно лучше использовать члена экземпляра, когда сможете. Они полезны, когда член экземпляра невозможен, поскольку:
- У вас нет доступа к источнику класса (это класс другой стороны).
- Вы хотите определить его на интерфейсе, а не на классе.
- Вы хотите, чтобы его вызывали по null (избегайте, это неидиоматично в C#, хотя более распространено на других языках).
- Вы хотите определить его для отдельных случаев дженериков. Например, если я создал
MyDictionary<TKey, TValue>
, который реализовал IDictionary<TKey, TValue>
, я не могу определить метод plus
, который добавляет число к сохраненному значению, потому что это может работать только тогда, когда TValue является известным числовым типом. Я могу определить такой метод, как метод расширения, такой как int Plus<TKey>(this MyDictionary<TKey, int> dict, int addend)
, который затем появится как член экземпляра, когда TValue
является int, но не будет вмешиваться в использование MyDictionary
для других параметров типа.
Все эти случаи не дают вам выбора, кроме как использовать метод расширения, но не используют их, когда член экземпляра выполнит задание. Это понятно, тем более, что некоторые другие языки .NET будут видеть только член расширения как статический.
Почтовый код, который на самом деле компилируется, поэтому мы можем сделать снимок с возможным ответом. –