Какова цель сокрытия (используя модификатор "new") объявления метода интерфейса? - PullRequest
13 голосов
/ 13 августа 2010

можно пометить объявление метода в интерфейсе как " new ", но имеет ли оно какой-либо "технический" смысл или это просто способ явно заявить, что объявление не может переопределить предыдущее?

Например:

interface II1
{
    new void F();
}

interface II2 : II1
{
    new void F();
}

допустимо (компилятор C # 4.0 не жалуется), но, похоже, не отличается от:

interface II1
{
    void F();
}

interface II2 : II1
{
    void F();
}

Заранее спасибодля любой информации.

РЕДАКТИРОВАТЬ: знаете ли вы сценарий, в котором было бы полезно скрытие в интерфейсе?

РЕДАКТИРОВАТЬ: По этой ссылке: Является ли метод сокрытия когда-либо хорошей идеей (спасибо Скотту), наиболее распространенным сценарием является эмуляция ковариантного возвращаемого типа.

Ответы [ 6 ]

8 голосов
/ 13 августа 2010

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

'II2.F ()' скрывает унаследованный член 'II1.F ()'.Используйте новое ключевое слово, если целью было скрытие.

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

6 голосов
/ 13 августа 2010

Два очень разные. Используя 'new', вы создаете новую цепочку наследования. Это означает, что любые реализации II2 должны будут реализовывать обе версии F(), и фактическая версия, которую вы в конечном итоге вызываете, будет зависеть от типа ссылки.

Рассмотрим следующие три реализации:

    class A1 : II1
    {
        public void F()
        {
            // realizes II1.F()
        }
    }

    class A2 : II2
    {
        void II1.F()
        {
            // realizes II1.F()
        }

        void II2.F()
        {
            // realizes II2.F()
        }
    }

    class A3 : II2
    {
        public void F()
        {
            // realizes II1.F()
        }

        void II2.F()
        {
            // realizes II2.F()
        }
    }

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

A2 a2 = new A2();
a2.F(); // invalid as both are explicitly implemented
((II1) a2).F(); // calls the II1 implementation
((II2) a2).F(); // calls the II2 implementation

Если у вас есть ссылка на A3, вы сможете напрямую вызывать версию II1, поскольку она подразумевается:

A3 a3 = new A3();
a3.F(); // calls the II1 implementation
((II2) a3).F(); // calls the II2 implementation
4 голосов
/ 13 августа 2010

Я знаю одно хорошее применение для этого: у вас есть , чтобы сделать это, чтобы объявить интерфейс COM, производный от другого интерфейса COM.Это затронуто в этой журнальной статье .

Fwiw, автор совершенно неверно определяет источник проблемы, это не имеет никакого отношения к «налогу на наследство».COM просто использует способ, которым типичный компилятор C ++ реализует множественное наследование.Для каждого базового класса есть одна v-таблица, как раз то, что нужно COM.CLR не делает этого, он не поддерживает MI, и есть только одна v-таблица.Методы интерфейса объединены в v-таблицу базового класса.

1 голос
/ 18 мая 2014

Я использую его почти во всех моих интерфейсах.Смотрите здесь:

interface ICreature
{
    /// <summary>
    ///     Creature's age
    /// </summary>
    /// <returns>
    ///     From 0 to int.Max
    /// </returns>
    int GetAge();
}

interface IHuman : ICreature
{
    /// <summary>
    ///     Human's age
    /// </summary>
    /// <returns>
    ///     From 0 to 999
    /// </returns>
    new int GetAge();
}

Абсолютно нормально иметь наследуемого члена с меньшими требованиями, но с большими обязательствами.ЛСП не нарушается.Но если да, то где документировать новый контракт?

1 голос
/ 02 декабря 2013

Пример, следующий за ответом Фредрика. Я хочу иметь интерфейс, который представляет метод для получения сущности по идентификатору. Затем я хочу, чтобы и WCF-сервис, и какой-то другой стандартный репозиторий могли использоваться в качестве этого интерфейса. Чтобы играть с WCF, мне нужно украсить свой интерфейс атрибутами. С точки зрения намерений, я не хочу украшать свой интерфейс вещами WCF, когда он не будет использоваться только через WCF, поэтому мне нужно использовать новый. Вот код:

public class Dog
{
    public int Id { get; set; }
}

public interface IGetById<TEntity>
{
    TEntity GetById(int id);
}

public interface IDogRepository : IGetById<Dog> { }

public class DogRepository : IDogRepository
{
    public Dog GetById(int id)
    {
        throw new NotImplementedException();
    }
}

[ServiceContract]
public interface IWcfService : IGetById<Dog>
{
    [OperationContract(Name="GetDogById")]
    new Dog GetById(int id);
}
1 голос
/ 13 августа 2010

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

С Спецификация языка C # 3.0

10.3.4 Новый модификатор Объявление члена класса разрешено объявлять членом с тем же именем или подписью, что и унаследованный член. Когда это происходит, говорят, что член производного класса скрывает член базового класса. Скрытие унаследованного члена не считается ошибкой, но это заставляет компилятор выдавать предупреждение. Для подавления предупреждения объявление производного члена класса может включать новый модификатор, указывающий, что производный член предназначен для скрытия базового члена. Эта тема обсуждается далее в §3.7.1.2. Если в объявление включен новый модификатор, который не скрывает унаследованный элемент, выдается предупреждение на этот счет. Это предупреждение подавляется удалением нового модификатора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...