Необычный синтаксис переопределения членов в C # - PullRequest
4 голосов
/ 29 июня 2011

Итак, кто-то сказал мне, что хорошим способом устранения неоднозначностей в наследовании классов является использование следующей идиомы:

class INewList<T> : IList, IList<T>
{
   new T IList<T>.this[int index] { get; set; }
}

Я не совсем понимаю синтаксис List<T>.this.Чем это отличается от простого:

new T this[int index] { get; set; }

Являются ли эти два функционально различными?В первом примере, мне нужно предоставить реализацию для индексатора позже, или этот код просто говорит компилятору: «Эй, используйте реализацию индексатора в IList<T>, если есть сомнения»?

Ответы [ 5 ]

3 голосов
/ 29 июня 2011

Это называется явная реализация . Когда вы явно реализуете элемент интерфейса, он может быть вызван только через ссылку этого типа (или подтипа, см. Ниже), поэтому, другими словами, IList (неуниверсальные) ссылки не смогут вызывать первый пример у вас.

Вот пример того, как работает подтип:

void Main() {
    I2 myC = new C();
    myC.Operation();
}

interface I1 {
    void Operation();
}

interface I2 : I1 {  }

class C : I2 {
    void I1.Operation() {
        Console.WriteLine ("called operation");
    }
}

Если вы выполните это, вы увидите вывод консоли. Если myC был объявлен как C, он не будет работать.

(обновлено, чтобы добавить пример)

0 голосов
/ 29 июня 2011

Ваш пример кода довольно запутанный и не компилируется.Однако, чтобы ответить на ваш вопрос о синтаксисе List<T>.this:

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

public class Foo : IDisposable {
  public void Dispose() {
  }
}

public class Bar : IDisposable {
  public void Close() {
  }
  void IDisposable.Dispose() {
    Close();
  }
}

Оба класса реализуют IDisposable, но для утилизации Bar вам придется вызвать Close.Вы также можете привести его к IDisposable и затем вызвать Dispose.

var foo = new Foo();
foo.Dispose();

var bar = new Bar();
bar.Close();
((IDisposable) bar).Dispose();

Для классов Foo и Bar это может не иметь значения, если метод очистки вызывается Dispose или Close, но для класса File вы можете предпочесть Close вместо Dispose.Другое использование состоит в том, чтобы скрыть интерфейс, который вы должны реализовать для участия во взаимодействии между объектами, но вы не хотите быть видимым для потребителей вашего класса.Или вы можете использовать его, чтобы обойти реализацию нескольких интерфейсов с конфликтующими методами.

Вы можете прочитать о явной реализации интерфейса в MSDN.

0 голосов
/ 29 июня 2011

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

Скажем:

INewList<int> myList = new NewList<int>();
myList[1] = 2;   // Error, this[int index] is not implemented.
IList<int> myList2 = myList; // Cast as IList<int>
myList2[1] = 2;  // Succeeds, it'll call IList<T>.this[int index].
IList myList3 = myList; // Cast as IList
myList3[1] = 2;  // Error, neither this[int index] nor IList.this[int index] are not implemented.

Естественно, если вы DID либо реализовали, он вызвал бысоответствующий метод с явной реализацией, переопределяющей любые неявные.

0 голосов
/ 29 июня 2011

Он явно реализует индексатор интерфейса.

  • Явная реализация вызывает синтаксис Interface.XYZ
  • Имя индексатора this, поэтому оно становится Interface.this
0 голосов
/ 29 июня 2011

Это ссылка на this в качестве разработчика IList<T>.
В противном случае вы не могли бы вернуть T из этого свойства, так как была бы неоднозначность с реализацией "plain" ILIst

...