В C # при реализации интерфейса все члены неявно являются открытыми. Разве не было бы лучше, если бы мы могли указать модификатор доступности ( protected
, internal
за исключением, private
конечно), или вместо этого мы должны просто использовать абстрактный класс?
Не имеет смысла. Интерфейс - это договор с общественностью, что вы поддерживаете эти методы и свойства. Палка с абстрактными классами.
Интерфейсы не имеют модификаторов доступа в своих методах, оставляя их открытыми для любого подходящего модификатора доступа. Это имеет цель: оно позволяет другим типам определять, какие методы и свойства доступны для объекта, следующего за интерфейсом. Предоставление им защищенных / внутренних средств доступа нарушает назначение интерфейса.
Если вы непреклонны в том, что вам нужно предоставить модификатор доступа для метода, либо оставьте его вне интерфейса, либо, как вы сказали, используйте абстрактный класс.
Я знаком с Java, а не с C #, но с какой стати вам нужен частный член в интерфейсе? Он не может иметь никакой реализации и будет невидим для реализации классов, поэтому будет бесполезен. Существуют интерфейсы для определения поведения. Если вам нужно поведение по умолчанию, чем использовать абстрактный класс.
Если интерфейс является внутренним, все его элементы будут внутренними для сборки. Если вложенный интерфейс защищен, только подклассы внешнего класса могут получить доступ к этому интерфейсу.
Внутренние члены для интерфейса вне его декларирующей сборки были бы бессмысленными, равно как и защищенные члены для интерфейса вне его декларирующего внешнего класса.
Цель интерфейса - описать контракт между типом реализации и пользователями интерфейса. Внешние абоненты не будут заботиться и не должны заботиться о реализации, для чего предназначены внутренние и защищенные участники.
Для защищенных членов, которые вызываются базовым классом, абстрактные классы являются способом указания договора между базовыми классами и классами, которые наследуются от них. Но в этом случае детали реализации обычно очень актуальны, если только это не вырожденный чисто абстрактный класс (где все члены являются абстрактными), в этом случае защищенные члены бесполезны. В этом случае используйте интерфейс и сохраните единственный базовый класс для реализации типов на выбор.
internal
членов. Если сборка Foo может содержать интерфейс IWoozle
с internal
членами, и если она содержит пять реализаций IWoozle
, код в любом месте может передавать экземпляры IWoozle
и использовать его открытые члены, но код, который получил IWoozle
бы, будет знать, что он реализован в сборке Foo. Рассмотрим, например, гипотетический интерфейс IImmutableWoozle
. Возможно, что реализации могут не иметь общий базовый тип, но если реализации вне Foo не может быть, то ...IImmutableWoozle
не будет какой-то дурацкой изменчивой реализацией. IInternalWoozle
который реализует, IWoozle
и любой код в Foo, который использует любой IWoozle
может проверить, IInternalWoozle
также реализован ли для того, чтобы добраться до внутренних членов. .NET Framework делает это местами. Вы можете скрыть реализацию интерфейса, явно указав имя интерфейса перед именем метода:
public interface IInterface {
public void Method();
}
public class A : IInterface {
public void IInterface.Method() {
// Do something
}
}
public class Program {
public static void Main() {
A o = new A();
o.Method(); // Will not compile
((IInterface)o).Method(); // Will compile
}
}
public
модификатор в элементе интерфейса или явно реализованном методе интерфейса. Например, чтобы ваш код работал с .NET 4.5, просто public
удалите оба файла. o.Method()
скомпилировать? Может кто-нибудь объяснить это? Почему указание имени интерфейса скрывает реализацию интерфейса? Интерфейс - это контракт, которого придерживаются все реализующие классы. Это означает, что они должны придерживаться всего этого или ничего из этого.
Если интерфейс общедоступен, то каждая часть этого контакта должна быть общедоступной, в противном случае это будет означать один для друзей / внутренних классов и нечто отличное от всего остального.
Либо используйте абстрактный базовый класс, либо (если это возможно и практично) метод внутреннего расширения интерфейса .
internal
, то внешний код мог бы получать из сборочных ссылок на вещи этого типа и передавать такие ссылки обратно в методы сборки, сохраняя при этом безопасность типов, без внешний код должен знать что-либо о рассматриваемом классе. К сожалению, такой подход будет работать только в том случае, если ни одному из конкретных производных абстрактного класса не потребуется наследовать от чего-либо, что не происходит от этого абстрактного класса. Вы можете скрыть почти весь код, реализованный интерфейсами, для внешних сборок.
interface IVehicle
{
void Drive();
void Steer();
void UseHook();
}
abstract class Vehicle // :IVehicle // Try it and see!
{
/// <summary>
/// Consuming classes are not required to implement this method.
/// </summary>
protected virtual void Hook()
{
return;
}
}
class Car : Vehicle, IVehicle
{
protected override void Hook() // you must use keyword "override"
{
Console.WriteLine(" Car.Hook(): Uses abstracted method.");
}
#region IVehicle Members
public void Drive()
{
Console.WriteLine(" Car.Drive(): Uses a tires and a motor.");
}
public void Steer()
{
Console.WriteLine(" Car.Steer(): Uses a steering wheel.");
}
/// <summary>
/// This code is duplicated in implementing classes. Hmm.
/// </summary>
void IVehicle.UseHook()
{
this.Hook();
}
#endregion
}
class Airplane : Vehicle, IVehicle
{
protected override void Hook() // you must use keyword "override"
{
Console.WriteLine(" Airplane.Hook(): Uses abstracted method.");
}
#region IVehicle Members
public void Drive()
{
Console.WriteLine(" Airplane.Drive(): Uses wings and a motor.");
}
public void Steer()
{
Console.WriteLine(" Airplane.Steer(): Uses a control stick.");
}
/// <summary>
/// This code is duplicated in implementing classes. Hmm.
/// </summary>
void IVehicle.UseHook()
{
this.Hook();
}
#endregion
}
Это проверит код.
class Program
{
static void Main(string[] args)
{
Car car = new Car();
IVehicle contract = (IVehicle)car;
UseContract(contract); // This line is identical...
Airplane airplane = new Airplane();
contract = (IVehicle)airplane;
UseContract(contract); // ...to the line above!
}
private static void UseContract(IVehicle contract)
{
// Try typing these 3 lines yourself, watch IDE behavior.
contract.Drive();
contract.Steer();
contract.UseHook();
Console.WriteLine("Press any key to continue...");
Console.ReadLine();
}
}
Все ответы здесь более или менее говорят о том, что интерфейсы должны быть такими, они являются универсальными общедоступными спецификациями.
Это самая обсуждаемая тема, позвольте мне опубликовать два превосходных ответа, которые я нашел на SO, когда этот вопрос всплыл в моей голове.
Этот ответ дает пример того, как бессмысленно иметь неоднородные спецификаторы доступа для членов интерфейса в производных классах. Код всегда лучше технических описаний.
Для меня самое ужасное в принудительных элементах открытого интерфейса - то, что сам интерфейс может быть внутренним для сборки, но элементы, которые он предоставляет, должны быть открытыми. Джон Скит объясняет здесь, к сожалению, дизайн .
Это поднимает вопрос, почему не были интерфейсы, разработанные, чтобы иметь непубличные определения для участников. Это может сделать контракт гибким. Это очень полезно при написании сборок, в которых вы не хотите, чтобы определенные члены классов находились вне сборки. Я не знаю почему.
По моему мнению, это нарушает инкапсуляцию. Я должен реализовать методы как публичные, затем я реализую интерфейс. Я не вижу причин, чтобы заставить public в классе, который реализует интерфейс. (C #)