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

Действительные приложения слияния членов с новым ключевым словом в С#

Я использую С# с версии 1 и никогда не видел целесообразного использования скрытия элемента. Вы знаете что-нибудь?

4b9b3361

Ответ 1

Сценарий №1:

Представьте, что вы разрабатываете библиотеку времени выполнения для .NET 2.0. Теперь у вас есть дженерики. У вас есть интерфейс:

interface IEnumerable 
{
    IEnumerator GetEnumerator();
}

Вы хотите создать новый интерфейс

interface IEnumerable<T> 
{
    IEnumerator<T> GetEnumerator();
}

Теперь у вас есть три варианта.

1) Сделайте общую версию не связанной с не-универсальной версией.

2) Сделайте универсальную версию расширенной версией не общего. Теперь у вас есть два метода, которые отличаются только типом возврата. Измените имя GetEnumerator нового типа на GetEnumerator2(). Потому что это жарко. Каждый любит хороший "2" метод.

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

Все это плохой выбор. Что бы вы выбрали? Мы выбрали (3). Хорошо, что это вариант; не скрывая, этот вариант не был бы доступен.

Теперь вы можете утверждать, что этот конкретный пример сокрытия не был "стоит"; если это так, что бы вы сделали?

Скрытие метода позволяет выявлять улучшенные интерфейсы, не вызывая поломки при улучшении системы типов.

Сценарий №2:

Вы работаете в FrobCo. Вы создаете класс Frobber, который расширяет Blobber, который предоставляется вам хорошими людьми в BlobCo.

BlobCo пренебрегает тем, что на Blobber применяет метод Frobozzle(), но ваши клиенты любят frobozzle frobbers, поэтому вы добавляете метод Frobozzle() к производному классу Frobber.

BlobCo понимает, что их клиенты хотят, чтобы Бробобы Фробоззле добавляли не виртуальный метод Frobozzle() к базовому классу Blobber.

Теперь, что вы делаете, сотрудник FrobCo?

1) Удалите метод Frobozzle на Frobber, тем самым разбив ваших клиентов, которые полагались на вашу реализацию. Помните, BlobCo не знает, как Frobozzle Frobber; они только написали код, который знает, как Frobozzle a Blobber.

2) Whine to BlobCo, что они должны были сделать свой метод виртуальным. Надеюсь, когда-нибудь они что-нибудь с этим поделают.

3) Скрыть свой метод в производном классе.

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

Дальнейшее чтение:

http://blogs.msdn.com/ericlippert/archive/2008/05/21/method-hiding-apologia.aspx

Ответ 2

Сделать тип возврата более явным - например, SqlConnection.CreateCommand возвращает a SqlCommand, а не DbCommand. На самом деле, похоже, что это не объявлено new, но это будет один из немногих случаев, когда я буду использовать это; чаще всего это зло.

Другое использование: удалить унаследованные атрибуты из члена.

Ответ 3

У нас был класс, унаследованный от класса WebControl. Когда мы обновили с 3.5 до 4.0, то, что некоторые из наших атрибутов (в основном вокруг onclick и javascript) изменились довольно радикально.

Мы не могли изменить способ обработки AttributeCollection классом WebControl, поэтому мы реализовали те же методы и свойства AttributeCollection в нашей пользовательской коллекции и спрятали свойство AttributeCollection с нашими своя.

Ни один из кода доступа не изменился, и мы смогли правильно реализовать способы обработки атрибутов в наших классах. Теперь никто не должен знать, что мы сделали, чтобы решить проблему. Все, что им нужно знать, это то, что они называют Attributes.Add как обычно, и мы исправляем вещи под капотом.

Ответ 4

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

Ответ 5

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

Ответ 6

Иногда я делаю класс, полученный из чего-то в библиотеке базового класса, где базовый класс (по соображениям производительности) не использовал виртуальную функцию. В этом случае имеет смысл использовать "новый". Вот один пример (который соответствует тому, что говорил Марк Гравелл), сильно типизированное WeakReference:

public class WeakReference<T> : System.WeakReference
{
    public WeakReference(T target) : base(target) { }
    public WeakReference(T target, bool trackResurrection) : base(target, trackResurrection) { }
    #if !WindowsCE
    protected WeakReference(SerializationInfo info, StreamingContext context) : base(info, context) {}
    #endif
    public new T Target
    {
        get { return (T)base.Target; }
        set { base.Target = value; }
    }
}

В тех случаях, когда метод базового класса фактически является виртуальным, я думаю, что Microsoft предвидит случаи, когда базовый класс реализуется одной стороной, а производный класс реализуется второй стороной. Вторая сторона добавляет функцию "Foo" , а затем первая сторона добавляет еще одну функцию "Foo" , которая на самом деле делает что-то другое (поэтому переопределение не подходит). Затем, чтобы поддерживать совместимость с сторонним кодом, вторая сторона сохраняет свою функцию под именем "Foo" , несмотря на то, что она напрямую не связана с версией базового класса. В этом случае вторая сторона добавляет "новое" в свою декларацию.

Ответ 7

  • Когда новая версия типа реализует элемент, видимый для видимости, имя которого конфликтует с именем, которое вы использовали в производном типе.

  • Чтобы скрыть неприемлемую реализацию в базовом классе, из которого вы получаете.

    Например, KeyedCollection<TKey, TItem>.Contains(TItem item) наследуется от Collection<TItem> и поэтому является операцией O (n), а не операцией O (1), которую обычно предоставляет KeyedCollection<TKey, TItem>.Contains(TKey key).

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

    Поэтому может быть целесообразно реализовать "лучшую" версию:

    public new bool Contains(TItem item)
    {
        if (item == null) throw new ArgumentNullException("item");
    
        return this.Contains(GetKeyForItem(item));
    }