Реализация нескольких методов интерфейса класса-C # - PullRequest
24 голосов
/ 27 апреля 2010

Возможно ли в C # иметь класс, который реализует интерфейс, у которого объявлено 10 методов, но реализует только 5 методов, т.е. определяя только 5 методов этого интерфейса ??? На самом деле у меня есть интерфейс, который реализуется 3 класса, и не все методы используются всеми классами, так что если я мог бы исключить какой-либо метод ???

Мне нужно это. Это может звучать как плохой дизайн, но это не надеюсь. Дело в том, что у меня есть коллекция пользовательских элементов управления, которые должны иметь общее свойство, и исходя из этого, только я отображаю их во время выполнения. Поскольку это динамично, мне нужно управлять ими для этого, у меня есть Свойства. Некоторые свойства нужны немногим классам и не всем. И по мере увеличения элемента управления эти свойства могут увеличиваться, так что это необходимо для одного элемента управления, который мне нужен во всех без какого-либо использования. только фиктивные методы. Для того же самого я подумал, что если есть способ избежать этих методов в остальной части класса, это было бы здорово. Кажется, что нет другого способа, кроме как иметь абстрактный класс или фиктивные функции: - (

Ответы [ 11 ]

25 голосов
/ 27 апреля 2010

Вы можете сделать его абстрактным классом и добавить методы, которые вы не хотите реализовывать, как абстрактные методы.

Другими словами:

public interface IMyInterface
{
    void SomeMethod();
    void SomeOtherMethod();
}

public abstract class MyClass : IMyInterface
{
    // Really implementing this
    public void SomeMethod()
    {
        // ...
    }

    // Derived class must implement this
    public abstract void SomeOtherMethod();
}

Если все эти классы должны быть конкретными, а не абстрактными, вам придется выбросить NotImplementedException / NotSupportedException изнутри методов. Но гораздо лучшей идеей было бы разделить интерфейс так, чтобы реализации классов не приходилось это делать.

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

public interface IFoo
{
    void FooMethod();
}

public interface IBar()
{
    void BarMethod();
}

public class SmallClass : IFoo
{
    public void FooMethod() { ... }
}

public class BigClass : IFoo, IBar
{
    public void FooMethod() { ... }
    public void BarMethod() { ... }
}

Это, вероятно, тот дизайн, который вам действительно нужен.

18 голосов
/ 27 апреля 2010

Вы нарушаете использование интерфейсов. Для каждого общего поведения у вас должен быть отдельный интерфейс.

4 голосов
/ 27 апреля 2010

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

Например:

public interface IPet
{
   void Scratch();
   void Bark();
   void Meow();
}

public class Cat : IPet
{
    public void Scratch()
    {
        Console.WriteLine("Wreck furniture!");
    }

    public void Meow()
    {
       Console.WriteLine("Mew mew mew!");
    }

    void IPet.Bark()
    {
        throw NotSupportedException("Cats don't bark!");
    }
}

public class Dog : IPet
{
    public void Scratch()
    {
        Console.WriteLine("Wreck furniture!");
    }

    void IPet.Meow()
    {
       throw new NotSupportedException("Dogs don't meow!");
    }

    public void Bark()
    {
        Console.WriteLine("Woof! Woof!");
    }
}

С классами, определенными выше:

var cat = new Cat();
cat.Scrach();
cat.Meow();
cat.Bark(); // Does not compile


var dog = new Dog();
dog.Scratch();
dog.Bark();
dog.Meow(); // Does not compile.


IPet pet = new Dog();
pet.Scratch();
pet.Bark();
pet.Meow(); // Compiles but throws a NotSupportedException at runtime.

// Note that the following also compiles but will
// throw NotSupportedException at runtime.
((IPet)cat).Bark();
((IPet)dog).Meow();
4 голосов
/ 27 апреля 2010

Это невозможно. Но вы можете бросить NotSupportedException или NotImplementedException для методов, которые вы не хотите реализовывать. Или вы можете использовать абстрактный класс вместо интерфейса. Таким образом, вы можете предоставить реализацию по умолчанию для методов, которые вы не хотите переопределять.

public interface IMyInterface
{
  void Foo();

  void Bar();
}

public class MyClass : IMyInterface
{
  public void Foo()
  {
    Console.WriteLine("Foo");
  }

  public void Bar()
  {
    throw new NotSupportedException();
  }
}

Или ...

public abstract class MyBaseClass
{
  public virtual void Foo()
  {
    Console.WriteLine("MyBaseClass.Foo");
  }

  public virtual void Bar()
  {
    throw new NotImplementedException();
  }
}

public class MyClass : MyBaseClass
{
  public override void Foo()
  {
    Console.WriteLine("MyClass.Foo");
  }
}
3 голосов
/ 27 апреля 2010

Вы можете просто иметь методы, которые вы не хотите использовать, чтобы создать исключение NotImplementedException. Таким образом, вы все равно можете использовать интерфейс как обычно.

1 голос
/ 27 апреля 2010

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

interface IConfigurableVisibilityControl
{
    //check box that controls whether current control is visible
    CheckBox VisibleCheckBox {get;}
}


class MySuperDuperUserControl : UserControl, IConfigurableVisibilityControl
{
    private readonly CheckBox _visibleCheckBox = new CheckBox();

    public CheckBox VisibleCheckBox 
    {
        get { return _visibleCheckBox; }
    }
    //other important stuff
}

//somewhere else
void BuildSomeUi(Form f, ICollection<UserControl> controls)
{
    //Add "configuration" controls to special panel somewhere on the form
    Panel configurationPanel = new Panel();
    Panel mainPanel = new Panel();
    //do some other lay out stuff
    f.Add(configurationPanel);
    f.Add(mainPanel);

    foreach(UserControl c in controls) 
    {
        //check whether control is configurable
        IConfigurableOptionalControl configurableControl = c as IConfigurableVisibilityControl;
        if(null != configurableControl) 
        {
            CheckBox visibleConfigCB = configurableControl.VisibleCheckBox;
            //do some other lay out stuff
            configurationPanel.Add(visibleConfigCB);
        }
        //do some other lay out stuff
        mainPanel.Add(c);
    }
}
1 голос
/ 27 апреля 2010

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

0 голосов
/ 27 июня 2017

Помимо вышеупомянутых превосходных предложений по проектированию интерфейсов, если вам действительно необходимо реализовать некоторые из методов, можно использовать «методы расширения». Переместите методы, которые требуют реализации, за пределы вашего интерфейса. Создайте другой статический класс, который реализует их как статические методы с первым параметром как this interfaceObject. Это похоже на методы расширения, используемые в LINQ для интерфейса IEnumerable.

public static class myExtension {
    public static void myMethod( this ImyInterface obj, ... ) { .. }
...
}
0 голосов
/ 30 декабря 2016

Путем реализации одного из принципов SOLID, который является «Принципом разделения интерфейсов», при котором Интерфейс разбивается на несколько интерфейсов.

0 голосов
/ 27 апреля 2010

Я хочу динамически добавить элемент управления в мою форму, поскольку у меня есть это как мое требование. Я нашел код от здесь . Я отредактировал это, как мне было нужно. Итак, у меня есть класс IService, который имеет общие свойства. Это реализовано пользовательскими элементами управления. Которые показываются во время выполнения в другом проекте. Хм, для этого у меня есть другой общий интерфейс, который имеет свойства, которые используются проектом для отображения элементов управления. Немногим элементам управления требуются дополнительные методы или функции, например, для реализации контекстного меню, основанного на выборе пользователя во время выполнения. т.е. в проекте есть значения, которые будут переданы в качестве свойств элементу управления, и он будет отображен. Теперь это меню доступно только для одного элемента управления, остальные не имеют этого. Поэтому я подумал, есть ли способ не использовать эти методы во всех классах, а не в одном классе. Но звучит так, что мне нужно либо использовать фиктивные методы, либо абстрактный класс. хм, фиктивные методы были бы более предпочтительны для меня, чем абстрактный класс: - (

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