2012-01-11 3 views
-3

Здесь я читал о методах статического и экземпляра, но я не вижу ответа на этот конкретный вопрос (как зеленый, как это может быть).Лучшая практика для методов Static vs. Instance, когда требуются значения.

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

I.E.

class Foo 
{ 
    //properties 
    bar1; 
    bar2; 

    //method 
    sumbar1andbar2() 
    { 
     return bar1 + bar2; 
    } 
} 

Метод sumbar1andbar2 нуждается в свойствах класса Foo для присутствия. Это кажется немного бестолковым, чтобы сделать статический метод и назвать это таким образом, так как я вручную проходя член класса в методу класса:

Foo foo1 = new Foo(); 
foo1.bar1 = x; 
foo1.bar2 = y; 
sumbar1andbar2(foo1.bar1, foo1.bar2); 

Но хотя метод экземпляра ниже кажется намного чист, я «м не знают о чистой и простой способ, чтобы гарантировать, что оба bar1 и bar2 не равны нулю, что вызовет исключение:

Foo foo1 = new Foo(); 
foo1.bar1 = x; 
foo1.bar2 = y; 
sumbar1andbar2(); 

Однако метод экземпляра, кажется, даже лучше, если метод изменяет еще одно свойство класса, например, bar3.

+3

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

ответ

1

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

Теперь к актуальному вопросу: если одно или оба значения могут потенциально будут поступать из других экземпляров Foo, сделайте метод расчета статическим. В противном случае сделайте его методом экземпляра.

P.S. Если ваш метод возвращает значение, не имеет параметров и не создает побочных эффектов, подумайте о том, чтобы сделать его вычисляемым свойством вместо метода.

+0

Спасибо dasblinkenlight! Это то, что я искал. Инкапсуляция - это то, что я искал. Будучи самоучкой, я пропускаю некоторые из этих вещей, которые большинство людей, вероятно, учатся в курсе 101. –

2

Если поведение метода уникально для типа Foo (и не имеет смысла применимо в другом месте), или если оно изменяет состояние Foo, то вы, вероятно, должны сделать его методом экземпляра Foo.

Если общий расчет (например, ваш пример), где вы можете использовать его в другом месте, у вас есть несколько вариантов:

Сделать это статический метод на классе полезности, например,

public static class MyUtility { 
    public static Int32 Add(Int32 x, Int32 y) { return x + y; } 
} 

Сделать это extension method на Foo, это родительский класс или интерфейс, который определяет х и у, например,

// Use as follows: 
// var f = new Foo() { x = 5, y = 5 }; 
// var ten = f.MyUtility(); 
public static class MyUtility { 
    public static Int32 Add(this Foo foo) { return Foo.x + Foo.y; } 
} 
+0

Нет причин для создания метода расширения для вашего класса. –

+0

Согласен. Я не сказал, что должен. –

+0

Спасибо Крису! Что помогает. –

2

Если это относится к конкретному экземпляру, то он должен быть членом экземпляра (будь то метод, свойство или поле). Это наиболее распространенные случаи, поэтому примеров много.

Если это не относится к конкретному экземпляру, то члену экземпляра требуется экземпляр, который вы не будете использовать каким-либо другим способом.Хорошим примером является 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). Тем более, если это конечно.

Методы расширения - это статические методы, которые могут быть вызваны, как если бы они были членами экземпляра. Они очень удобны, но обычно лучше использовать члена экземпляра, когда сможете. Они полезны, когда член экземпляра невозможен, поскольку:

  1. У вас нет доступа к источнику класса (это класс другой стороны).
  2. Вы хотите определить его на интерфейсе, а не на классе.
  3. Вы хотите, чтобы его вызывали по null (избегайте, это неидиоматично в C#, хотя более распространено на других языках).
  4. Вы хотите определить его для отдельных случаев дженериков. Например, если я создал MyDictionary<TKey, TValue>, который реализовал IDictionary<TKey, TValue>, я не могу определить метод plus, который добавляет число к сохраненному значению, потому что это может работать только тогда, когда TValue является известным числовым типом. Я могу определить такой метод, как метод расширения, такой как int Plus<TKey>(this MyDictionary<TKey, int> dict, int addend), который затем появится как член экземпляра, когда TValue является int, но не будет вмешиваться в использование MyDictionary для других параметров типа.

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

+0

Отличная информация, спасибо Jon! –