Які практичні можливості використання «нового» модифікатора в C # щодо приховування?


21

Співробітник і я розглядали поведінку newключового слова в C #, як це стосується поняття приховування. З документації :

Використовуйте новий модифікатор, щоб явно приховати член, успадкований від базового класу. Щоб приховати спадковий член, оголосьте його у похідному класі, використовуючи те саме ім'я, та змініть його за допомогою нового модифікатора.

Ми прочитали документацію і зрозуміли, що вона в основному робить і як це робить. Те, що ми насправді не змогли вирішити, - це вам потрібно зробити це в першу чергу. Модифікатор існує з 2003 року, і ми обидва працювали з .Net довше, ніж це, і це ніколи не з'являється.

Коли така поведінка буде необхідною у практичному розумінні (наприклад: як це стосується ділової справи)? Це функція, яка пережила свою корисність, або це те, що вона просто досить незвична в тому, що ми робимо (зокрема ми робимо веб-форми та MVC-додатки та деякі невеликі факторні WinForms та WPF)? Спробувавши це ключове слово та граючи з ним, ми виявили певну поведінку, яка дозволяє йому виглядати трохи небезпечно, якщо їх не використовувати.

Це звучить трохи відкрито, але ми шукаємо конкретний випадок використання, який можна застосувати до бізнес-програми, яка вважає цей інструмент корисним.


9
Можливо, ви теж це прочитали, але є цікава стаття від Еріка Ліпперта (розробник компілятора C #) про те, чому приховування методу було додано до C #: blogs.msdn.com/b/ericlippert/archive/2008/05/21/… . Це відповідає на ваше запитання, але я не готова до вас ділової справи, тому я ставлю це до коментаря.
Джалайн

3
@Jalayn: Діловий випадок обговорюється Еріком у цьому дописі: blogs.msdn.com/b/ericlippert/archive/2004/01/07/…
Брайан

Відповіді:


22

Ви можете використовувати його для імітації коваріації типу повернення. Пояснення Еріка Ліпперта . Ерік надає такий приклад коду:

abstract class Enclosure
{
    protected abstract Animal GetContents();
    public Animal Contents() { return this.GetContents(); }
}
class Aquarium : Enclosure
{
    public new Fish Contents() { ... }
    protected override Animal GetContents() { return this.Contents(); }
}

Це обхід. public override Fish Contents() { ... }не є законним, незважаючи на те, що він безпечний.

Взагалі, ви не повинні використовувати метод приховування, оскільки це бентежить споживачів вашого класу (конкретний приклад вище не страждає від цієї проблеми). Просто назвіть свій новий метод чимось іншим, якщо ви не хочете переосмислити існуючий метод.

Ймовірна ситуація в реальному світі, коли вам знадобиться приховування методу, якщо постачальник базового класу додав загальний метод, який ви вже додали до похідного класу. Така програма буде компілювати (і давати попередження) без нового ключового слова, але додаючи new: "Я знаю, що моя версія цього методу замінює версію базового класу. Це жахливо і заплутано, але ми з цим застрягли". Це все ж краще, ніж змушувати похідний клас перейменувати їх метод.

Просто дозволити трактувати отриманий метод як переоцінку, це спричинить проблеми. Ігноруючи будь-які занепокоєння щодо реалізації компілятора, новий метод семантично відрізняється від базового методу, але поліморфізм спричинить виклик нового методу, коли його попросять викликати метод з такою ж назвою.

Ця ситуація детально обговорюється в цій публікації Еріком Ліппертом.


1
+1 за newте, що є маркером для "це жахливо і заплутано".
Авнер Шахар-Каштан

Я думаю, що приклад Еріка дуже корисний, хоча б тому, що я перебуваю в подібній ситуації ... У мене є базовий клас, що реалізує нетривіальний метод, який повертає TBase, і похідний клас, який повинен повернути TDerived. У цьому випадку він відчуває себе необхідним злом.
Кайл Баран

4

Я думаю, що це є на випадок, якщо вам це знадобиться, щоб зробити щось, про що дизайнери мови, можливо, не думали. C # багато в чому була реакцією на ранні версії Java. І одне, що зробила Java - це дуже чітко розробити розробників голубів, щоб усунути можливості розробників, що стріляють собі в ноги. C # взяв дещо інший підхід і дав розробникам трохи більше сил, що дозволило розробникам ще кілька можливостей зняти себе в ноги. Одним із прикладів є unsafeключове слово. Це newключове слово є іншим.

Тепер, мабуть, це не так корисно, як, unsafeале коли ви потрапите в специфікацію мови, важко вибратися з мовної специфікації.


5
У Java немає нового, оскільки Java трактує всі методи як віртуальні. За словами Еріка Ліпперта, мотивація підтримки нового полягає у вирішенні проблеми крихкого базового класу. Існування нового необхідне для використання в реальному бізнесі, а не лише для бібліотеки низького рівня. У Java немає нових (і не мають невіртуальних методів) означає, що якщо базовий клас вводить новий метод, який вже використовується у похідних класах, існуючий код може зламатися, незважаючи на те, що розробнику базового класу слід дозволити не забувати код, який його споживає.
Брайан

3

Це говорить читачеві, що "я навмисно приховав базовий клас" реалізацію цього методу ", на відміну від випадково.


5
Це вражає мене як прохання питання. ОП знає, що робить, але хоче знати, чому.
Брайан

0

Ви можете мати попереднього учасника доступним через інше ім’я:

class VehicleClass
{
  public int AnyProperty
  {
    get; set;
  }

  public int AnyFunction() { return 0; }
} // VehicleClass

class IntermediateClass : VehicleClass
{
  public int PreviousAnyProperty
  {
    get { return AnyProperty; }
    set { AnyProperty = value  }
  }

  public int PreviousAnyFunction() { return AnyFunction(); }
} // IntermediateClass 

class CarClass : IntermediateClass
{
  public new int AnyProperty
  {
    get ; set ;
  }

  public new int AnyFunction() { return 5; }
} // class CarClass

class ExampleClass
{

  public static void Main()
  {
    using (CarClass MyCar = new CarClass())
    {
      int AnyInt1 = MyCar.PreviousAnyProperty;
      MyCar.PreviousAnyProperty = 7;

      int AnyInt2 = MyCar.PreviousAnyFunction();

      int AnyInt3 = MyCar.AnyProperty;
      MyCar.AnyProperty = 45;

      int AnyInt4 = MyCar.AnyFunction();
    }
  } // static void Main()

} // class CarClass

Ура.


Мені знайоме, як це працює, але моє запитання справді таке: Чому ви хочете, щоб попередній член був доступний через інше ім’я? Це розриває всі види контрактів, робить певні загальні штуки марними.
Джоел Етертон

@Joel Etherton: Як ви можете знати Alredy, інколи розробникам доводиться "вибирати" код програмного забезпечення інших людей. І ми можемо не мати права змінювати, можливо, розширювати заняття. І може знадобитися використання обох, попереднього учасника та нового.
umlcat

0

Я вважаю це досить корисним під час створення тестового набору для застарілого коду. Це дозволяє мені приховати зовнішні залежності, як запит до бази даних всередині методу, який використовується іншими методами. Щоб мати можливість протестувати інші методи, я можу приховати оригінальну логіку, яка залежить від зовнішніх ресурсів, не потрібно додавати віртуальне ключове слово до цих методів у тестових класах.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.