Интерфейс в C # - PullRequest
       22

Интерфейс в C #

8 голосов
/ 29 января 2010

Я новичок в ООП и у меня есть несколько вопросов.

  1. Почему методы, объявленные в интерфейсе, не имеют модификаторов (public, private и т. Д.).

  2. В этом коде:

class Program
{
    static void Main(string[] args)
    {
        X ob = new Y();
        ob.add(4, 5);
        Z ob1 = new Y();
        ob1.mull(2, 3);
        Console.Read();
    }
}

public interface X
{
    void add(int x, int y);
}
public interface Z
{
    void mull(int x, int y);
}

class Y : X, Z
{
    void X.add(int x, int y)//here we are not decalring it as public ,why?
    {
        Console.WriteLine("sum of X and y is " + (x + y));
    }
    void Z.mull(int x, int y)
    {
        Console.WriteLine("product of X and Y is" + (x * y));
    }
}

Оба метода не требуют модификаторов, но когда я не использую интерфейс, как X.add() выше, мне нужно сделать реализацию общедоступной. Почему?

Ответы [ 8 ]

34 голосов
/ 29 января 2010

Интерфейс - это контракт. Он говорит: «Я могу сделать это». Какой смысл кому-то вручать вам экземпляр IInterface, в котором вы не можете использовать некоторые методы этого контракта, потому что они были помечены как не публичные?

Это обоснование для разработки языка таким способом. Спецификация для этого находится в §13.2 спецификации языка:

Все члены интерфейса неявно имеют открытый доступ. Это ошибка времени компиляции для объявлений членов интерфейса, чтобы включить любые модификаторы. В частности, элементы интерфейса не могут быть объявлены с модификаторами abstract, public, protected, internal, private, virtual, override или static.

Что касается вашего кода, это пример явной реализации интерфейса . Это наиболее полезно, когда класс или структура реализуют два интерфейса, каждый из которых имеет член с одинаковой сигнатурой. Например, IEnumerable и IEnumerable<T> определяют метод GetEnumerator, не принимающий параметров.

public interface IEnumerable {
    IEnumerator GetEnumerator();
}

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

Обратите внимание, что согласно приведенным выше определениям любой класс, который реализует IEnumerable<T>, должен также реализовывать IEnumerable. Имейте в виду, что тип возвращаемого значения не является частью подписи, и поэтому у нас есть конфликт с IEnumerable.GetEnumerator и IEnumerable<T>.GetEnumerator. Вот что должна решить явная реализация интерфейса:

class X<T> : IEnumerable<T> {
    List<T> _list = new List<T>();
    public IEnumerator<T> GetEnumerator() {
        return _list.GetEnumerator();
    }

    IEnumerator GetEnumerator() {
        return GetEnumerator(); // invokes IEnumerable<T>.GetEnumerator
    }
}

Члены, которые являются явными реализациями интерфейса, видны только через экземпляр интерфейса. Таким образом:

X<int> x = new X<int>();
var e1 = x.GetEnumerator(); // invokes IEnumerable<int>.GetEnumerator
                           // IEnumerable.GetEnumerator is not visible
IEnumerable y = x;
var e2 = y.GetEnumerator(); // invokes IEnumerable.GetEnumerator

Таким образом, в вашем коде

X ob = new Y();
ob.add(1, 2); // X.add is visible through interface
Y y = new Y();
y.add(1, 2); // compile-time error, X.add is not visible

Оба метода не требуют модификаторов, но когда я не использую интерфейс, как X.add () выше, мне нужно сделать реализацию общедоступной. Почему?

Хорошо, не совсем понятно, о чем вы здесь спрашиваете. Модификаторы доступа не допускаются для явных реализаций интерфейса. Это 13.4:

Это ошибка времени компиляции для явной реализации элемента интерфейса, которая включает модификаторы доступа, и это ошибка времени компиляции, чтобы включить модификаторы abstract, virtual, override или static.

Если реализация интерфейса не помечена как явная реализация интерфейса, то она должна иметь модификатор доступа public. Это 13.4.4 (Отображение интерфейса):

Отображение интерфейса для класса или структуры C находит реализацию для каждого члена каждого интерфейса, указанного в списке базовых классов C. Реализация конкретного элемента интерфейса I.M, где I является интерфейсом, в котором объявлен элемент M, определяется путем изучения каждого класса или структуры S, начиная с C и повторяя для каждого последующего базовый класс C, пока не будет найден матч

  • Если S содержит объявление явной реализации элемента интерфейса, которая соответствует I и M, то этот элемент является реализацией I.M

  • В противном случае, если S содержит объявление нестатического открытого члена, совпадающего с M, то этот элемент является реализацией I.M.

Ошибка времени компиляции происходит, если реализации не могут быть найдены для всех членов всех интерфейсов, указанных в списке базовых классов C.

Итак, вкратце, компилятор сначала ищет явную реализацию интерфейса. Если он не может найти его, он ищет нестатический, открытый член с той же сигнатурой, что и у реализуемого метода M. Если это не может найти один, происходит ошибка времени компиляции. Так что правила таковы. Для реализации члена интерфейса I.M:

  1. Если вы реализуете I.M явно, то синтаксис будет

    return-type I.M(parameter-list)

  2. В противном случае синтаксис будет

    public return-type M(parameter-list)

Таким образом, с

interface IAdd {
    int Add(int x, int y)
}

Мы можем реализовать явно:

class Explicit : IAdd {
    int IAdd.Add(int x, int y) { return x + y; }
}

или нет:

class NotExplicit : IAdd {
    public int Add(int x, int y) { return x + y; }
}

Разница в том, что Explicit.Add не отображается, если только экземпляры Explicit не набраны как IAdd:

IAdd explicitInterface = new Explicit();
explicitInterface.Add(2, 2);
Explicit explicit = new Explicit();
explicit.Add(2, 2); // compile-time error
* * В то время как одна тысяча сто двадцать пять * * тысяча сто двадцать шесть
IAdd notExplicitInterface = new NotExplicit();
notExplicitInterface.Add(2, 2);
NotExplicit notExplicit = new NotExplicit();
notExplicit.Add(2, 2); // okay, NOT a compile-time error as above

Это помогает?

2 голосов
/ 29 января 2010

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

Возможно, вы захотите взглянуть на следующие вопросы:

Как я узнаю, когда создавать интерфейс?
Почему я не могу иметь защищенные элементы интерфейса?

1 голос
/ 29 января 2010

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

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

Если вы удалите «X». из вашей реализации X.Add вы сможете «видеть» и использовать интерфейс без явного приведения. Это «неявная» реализация интерфейса. Пока у вас нет конфликтов имен или какой-либо причины сделать элементы интерфейса немного менее видимыми для обычных клиентов, вы, вероятно, предпочтете неявную реализацию интерфейса.

1 голос
/ 29 января 2010

Поскольку ваши два интерфейса не определяют методы с одинаковой сигнатурой, вам не требуется явная реализация. Вы можете сделать следующее:

public void add(int x, int y)
{
    Console.WriteLine("sum of X and y is " + (x + y));
}
public void mull(int x, int y)
{
    Console.WriteLine("product of X and Y is" + (x * y));
}

Это неявная реализация интерфейса, и теперь эти методы проще вызывать в экземпляре вашего класса. Просто вызовите myInstance.add(1, 2) вместо того, чтобы приводить myInstance в качестве экземпляра интерфейса X.

1 голос
/ 29 января 2010

Прямо с Microsoft : «Члены интерфейса всегда общедоступны, поскольку цель интерфейса - предоставить другим типам доступ к классу или структуре.»

1 голос
/ 29 января 2010

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

0 голосов
/ 29 января 2010

Это разница между Explict и Implict реализацией интерфейса.

Обычно вы захотите реализовать интерфейс неявным образом, что означает, что внедренные члены доступны публично. Это имеет смысл, если учесть, что реализация интерфейса обычно означает, что класс может выполнять заданную функцию (например, избавиться от IDisposable).

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

0 голосов
/ 29 января 2010

Поскольку функции, поля и т. Д., Объявленные в интерфейсе, по умолчанию всегда имеют общедоступный модификатор. Таким образом, при его реализации вам не нужно вводить public, потому что метод class уже сейчас является реализацией интерфейса, поэтому его public. В классах все поля и методы являются частными, но не имеют значения.

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