Какова цель скрытия (с использованием "нового" модификатора) декларации метода интерфейса?

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

Например:

interface II1
{
    new void F();
}

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

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

interface II1
{
    void F();
}

interface II2 : II1
{
    void F();
}

Заранее благодарим за любую информацию.

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

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

Ответы

Ответ 1

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

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

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

Ответ 2

Оба они очень разные. Используя "новый", вы создаете новую цепочку наследования. Это означает, что для любых реализаций 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

Ответ 3

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

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

Ответ 4

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

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

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

Ответ 5

Пример, следующий за Fredrik. Я хочу иметь интерфейс, представляющий метод для получения объекта по id. Затем я хочу, чтобы как служба 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);
}

Ответ 6

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

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

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

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