Какова цель скрытия (с использованием "нового" модификатора) декларации метода интерфейса?
можно пометить объявление метода в интерфейсе как " новый", но имеет ли он какой-либо "технический" смысл или это просто способ явно заявить, что объявление не может переопределить предыдущий
Например:
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 не нарушается. Но если да, то где документировать новый контракт?