C #: необязательный метод - PullRequest
       93

C #: необязательный метод

3 голосов
/ 28 октября 2009

У меня есть объект, который реализует интерфейс. Я хочу вызвать метод объекта, если он реализован. Как лучше всего это сделать?

Обновление Некоторые из вас упоминали, что мой вопрос был неопределенным. Извини за это. Когда я сказал «если он реализован», я имел в виду «если он вызывается». Спасибо за ваши ответы и усилия, ребята (или девушки!). Я поражен тем, сколько поддержки разработчиков есть на этом сайте.

Ответы [ 12 ]

13 голосов
/ 28 октября 2009

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

12 голосов
/ 28 октября 2009

Не совсем уверен, что вы подразумеваете под «если это реализовано». Если метод находится в интерфейсе, а ваш объект реализует интерфейс, он должен реализовать метод.

10 голосов
/ 28 октября 2009

Если вы хотите проверить, реализует ли объект интерфейс, чтобы вы могли вызвать метод, вы можете сделать это так:

interface IFoo { void Bar(); }

object o = GetObjectThatMayImplementIFoo();
IFoo foo = o as IFoo;

if (foo != null) {
  foo.Bar();
}

Я думаю, это то, что вы спрашивали?

7 голосов
/ 28 октября 2009

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

4 голосов
/ 28 октября 2009

Я думаю, что вы действительно ищете частичный метод. Это новое в .NET 3.5. Вы просто объявляете метод как «частичный»:

partial void OnLoaded();

Метод можно вызывать как обычно:

OnLoaded();

Замечательно, что если метод нигде не реализован, компилятор достаточно умен, чтобы не генерировать вызов.

Это было реализовано в основном для LINQ to SQL и для Entity Framework; это позволяет сгенерированному коду (используя частичные классы) определять и вызывать методы, не зная, реализованы ли они.

Было бы интересно смешивать частичные методы с интерфейсами (я не пробовал), но моей первой попыткой было бы объявить частичный метод в интерфейсе.

2 голосов
/ 28 октября 2009

Мой первый ответ: не делай этого. Он создает условную логику вокруг возможности присутствия метода, он идет вразрез со статической типичностью C # и нарушает пару принципов SOLID. Мой опыт подсказывает мне, что это неправильный путь.

С учетом сказанного это можно сделать с помощью Reflection или с помощью решения "is / as", которое демонстрирует wojo.

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

2 голосов
/ 28 октября 2009

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

2 голосов
/ 28 октября 2009

Разве класс объекта не должен реализовывать каждый метод интерфейса?

Если класс объекта наследуется от абстрактного класса, возможно, он не сможет переопределить («реализовать») некоторые методы. Возможно, вы смешиваете два в своем уме.

1 голос
/ 28 октября 2009

Эй, ребята, не забывайте ключевое слово "is": P

Вы можете проверить, реализует ли объект интерфейс, подобный этому:

if (inst is IInterface) 
{
  // you can safely cast it
}

Я предпочитаю так, но, конечно, вы также можете использовать ключевое слово "as"

IInterface a = inst as IInterface;
if (a != null) 
{
  // use a, already casted
}
1 голос
/ 28 октября 2009

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

-> иметь несколько интерфейсов и посмотреть, реализует ли их класс; это, вероятно, самый чистый способ справиться с этим, но он может оставить вас с большим количеством различных интерфейсов, что может быть нежелательно:

IIntfA = inst as IIntfA;
if (inst != null) {
  // inst seems to be implemented
}

-> Используйте методы в стиле TryXxx, которые возвращают true, если они были успешными (например, TryParse() и т. Д.).

-> Использовать NotImplementedException - но учтите, что перехват этих данных очень дорогой и должен использоваться только для вызовов, которые выполняются редко или когда не ожидается отсутствующая реализация. Класс Stream работает так, например, если он не может быть записан (но, кроме того, есть свойство, указывающее, что класс поддерживает, например, IsWritable в классе Stream).

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