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

2

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

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

Теги:
oop

12 ответов

10
Лучший ответ

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

  • 2
    Дочерние классы все еще будут иметь реализацию виртуального метода. Это будет реализация базового класса.
12

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

  • 0
    Должна быть реализация, но она вполне может просто сгенерировать исключение NotImplementedException, фактически говорящее о том, что на самом деле не существует доступной реализации ... посмотрите, например, класс Stream в каркасе (который является не интерфейсом, а абстрактным классом). , но концепция одинакова для обоих).
  • 1
    Но в любом случае это все еще реализовано в том, что касается компилятора, так в чем же вопрос?
Показать ещё 2 комментария
10

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

interface IFoo { void Bar(); }

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

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

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

  • 3
    Обратите внимание , что модель is затем бросок не рекомендуется, вы должны использовать в as и проверить null (более высокую производительность , так как среда выполнения не выполняет две преобразованием типов).
  • 0
    Правда, я сам этим не пользуюсь, не уверен, почему я так написал. Обновлено!
Показать ещё 1 комментарий
7

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

4

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

partial void OnLoaded();

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

OnLoaded();

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

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

Смешивание частичных методов с интерфейсами было бы интересным (я его не пробовал), но моя первая попытка заключается в объявлении частичного метода в интерфейсе.

  • 0
    +1. Этот ответ и придумал моя интуиция.
  • 3
    Я сомневаюсь, что это то, что ему нужно. Предполагается, что частичные методы используются для установки необязательных «обратных вызовов» между двумя частями одного и того же класса (где одна обычно генерируется, а другая кодируется вручную). У них много ограничений - только приватные, возврат по void и т. Д. Они определенно не имеют никакого отношения к интерфейсам.
Показать ещё 1 комментарий
2

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

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

2

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

2

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

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

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

1

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

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

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

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

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

  • 1
    Вы пропустили имя переменной
1

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

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

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

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

IInterface a = inst as IInterface;
if (a != null) 
{
  // use a, already casted
}
0

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

Итак, если вы хотите протестировать реализацию определенного интерфейса (ISomething) своим объектом (yourObj), одним из вариантов является проверка типа данных с использованием отражения. Основываясь на результатах этого теста, вы можете явно использовать объект реализации в интерфейсе Type и использовать его члены...

if (yourObj is ISomething)
     ((ISomething)yourObj).DoSomething();

Это то же самое сделано другим способом (более "многословным" с помощью вызовов методов):

if (typeof(ISomething).IsAssignableFrom(yourObj.GetType()))
    ((ISomething)yourObj).DoSomething();

В этом примере предполагается, что интерфейс ISomething определяется как:

public interface ISomething {
    void DoSomething();
    // other members ...
}

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

0

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ConsoleApplication1
{
    public static class Program
    {
        static void Main(string[] args)
        {
            EmployeeA empA = new EmployeeA();

            if (empA.IsImplemented("TestMethod"))
                empA.TestMethod();

            EmployeeB empB = new EmployeeB();
            if (empB.IsImplemented("TestMethod"))
                empB.TestMethod();


            Console.ReadLine();

        }

        public static bool IsImplemented(this IEmp emp, string methodName)
        {
            ImplementedAttribute impAtt;
            MethodInfo info = emp.GetType().GetMethod(methodName);
            impAtt = Attribute.GetCustomAttribute(info, typeof(ImplementedAttribute), false)
                        as ImplementedAttribute;

            return (impAtt == null) ? true : impAtt.Implemented;

        }

    }

    public class EmployeeA : IEmp
    {
        #region IEmp Members

        [Implemented(false)]
        public void  TestMethod()
        {
            Console.WriteLine("Inside of EmployeeA");
        }

        #endregion
    }

    public class EmployeeB : IEmp
    {
        #region IEmp Members

        [Implemented(true)]
        public void TestMethod()
        {
            Console.WriteLine("Inside of EmployeeB");
        }

        #endregion
    }


    public class ImplementedAttribute : Attribute
    {
        public bool Implemented { get; set; }

        public ImplementedAttribute():this(true)
        {
        }

        public ImplementedAttribute(bool implemented)
        {
            Implemented = implemented;
        }
    }

    public interface IEmp
    {
        void TestMethod();
    }

}

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

  • 0
    Ой спасибо! Очень интересное решение.
Сообщество Overcoder
Наверх
Меню