В чем разница между созданием объекта класса и интерфейса (см. следующий пример)? - PullRequest
2 голосов
/ 23 января 2011
interface i1
{
    void add();
}

class abc : i1
{
    public void add()
    {
        Console.WriteLine("hi! add");
    }
}

теперь в Main Я создаю два объекта, например:

abc obj1 = new abc();

и

i1 obj2 = new abc();

Скажите, пожалуйста, в чем разница между двумя приведенными выше примерами?

Ответы [ 6 ]

9 голосов
/ 23 января 2011

Разница в том, что obj1 вводится как экземпляр abc, а obj2 - как экземпляр i1.Обе эти переменные являются ссылками на экземпляры abc, но разница заключается в том, что доступно в коде.Допустим, у вас есть следующее:

interface IFoo { void Bar(); }
public class Foo : IFoo {
    public void Bar() { Console.WriteLine("Foo.Bar!"); }
    public void Baz() { Console.WriteLine("Baz!"); }
}

Тогда:

Foo foo = new Foo();
IFoo iFoo = new Foo();

Тогда допустимо следующее:

foo.Baz();

но это не так:

iFoo.Baz(); // compile-time error

Дело в том, что компилятор не знает, что референт iFoo на самом деле Foo и поэтому имеет метод Baz.В частности, обратите внимание, что это возможно:

public class FooFoo : IFoo {
    public void Bar() { Console.WriteLine("FooFoo.Bar!"); }
}

IFoo foofoo = new FooFoo();
foofoo.Baz(); // not legal

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

2 голосов
/ 23 января 2011

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

В первом примере:

abc obj1 = new abc();

У вас будет доступ к следующему:

  • Публичные члены abc
  • Защищенные члены abc, если вызваны из производного класса abc
  • Внутренние элементы abc, если вызваны из той же сборки
  • Приватные члены abc, если вызваны из других источников внутри самого abc класса

Вы будете не иметь доступ ко всем явно реализованным элементам интерфейса.

Во втором примере:

i1 obj2 = new abc();

У вас будет доступ только к тем членам, которые определены в интерфейсе i1

1 голос
/ 23 января 2011

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

Однако, скажем, abc реализовал другие интерфейсы, кроме i1:

interface i1 { void add(); }
interface i2 { void subtract(); }

class abc : i1, i2
{
    public void add() { ... }
    public void subtract() { ... }
}

СейчасЕсли вы повторяете свои экземпляры:

abc obj  = new abc();
i1  obj1 = new abc();
i2  obj2 = new abc();

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

  • Вы можетепозвоните на номера add и subtract на obj;
  • Вы можете позвонить add на obj1;
  • Вы можете позвонить subtract на obj2;

Это потому, что тип интерфейса дает вам только «частичное представление» о конкретном типе.(Хотя это звучит как ограничение, на самом деле это хорошая вещь, потому что позволяет явно указать, например, в списке параметров метода, какое поведение или контракт вы ожидаете от этого параметра;требуется или планируется сделать с этим параметром.)

1 голос
/ 23 января 2011

Интерфейс определяет контракт между вызывающим абонентом и вызываемым абонентом.Любой объект, который реализует этот интерфейс, также реализует контракт.Таким образом, вы также можете иметь

class cde : i1 { public void add() { console.writeline("cde add!"); } }

и затем иметь функцию:

void myFunction(i1 adder) { adder.add(); }

, которая вызывается следующим образом:

i1 myAbc = new abc();
i1 myCde = new cde();
myFunction(myAbc);
myFunction(myCde);

Даже если два класса реализуют i1они оба реализуют один и тот же контракт и, следовательно, myFunction может вызывать методы для любого из них.

0 голосов
/ 24 января 2011

Самым большим отличием является то, что obj1 сможет содержать только объекты типа «abc» или производного от них типа, тогда как obj2 сможет содержать любой объект, реализующий «i1». Следующее по величине отличие состоит в том, что obj1 может быть передан методам, которые ожидают «abc» или «i1», тогда как obj2 может быть передан только методам, которые ожидают «i1».

Обратите внимание, что хотя obj1 и obj2 изначально будут содержать объекты типа "abc", но это не означает, что они никогда не будут содержать другие объекты, которые могут быть других типов. Поскольку obj2 будет позволено хранить объекты типов, отличных от «abc», независимо от того, действительно ли он когда-либо делает это, компилятор не разрешит передавать его методам, которые требуют «abc».

0 голосов
/ 23 января 2011

Различие, связанное с интерфейсом, состоит в том, что если abc реализует что-либо кроме i1 (некоторый другой интерфейс или просто другие методы или открытые члены), вы сможете получить к ним доступ для obj1, но не для obj2.

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