#c# #interface #overriding #implementation #abstract
#c# #интерфейс #переопределение #реализация #аннотация
Вопрос:
Мне нужно разработать около 5 разных классов.
Многие части этих классов будут очень похожи, но у них будут небольшие различия (конечно).
Если я напишу, interface
что реализует каждый из разработанных мной классов, то каждый abstract
метод в interface
должен быть полностью написан.
Если я напишу base
класс, от которого происходит каждый из разработанных мной классов, то каждый класс автоматически будет обладать некоторой функциональностью в virtual
методе, который я создаю в base
классе, но все они должны быть переопределены, вызывая base
функциональность, чтобы включить небольшие различия.
Есть ли способ объединить эти функции? Мне нравится требовать, чтобы методы interface
были реализованы, но мне также нравится, когда набор функций предварительно запрограммирован base
классом.
Я просмотрел множество примеров здесь и в других местах, но не похоже, что кто-то делает то, что я описываю. Возможно ли это вообще?
РЕДАКТИРОВАТЬ: Итак, учитывая это:
abstract class Base
{
virtual protected void OptionallyOverridable() {}
abstract protected void SubclassMustImplement();
}
… есть ли способ написать что-то подобное:
abstract class Base2
{
DataEventType EventType;
DataChangedEventHandler OnDataChange;
virtual protected void OptionallyOverridable() {}
abstract protected void SubclassMustImplement() {
// values here are guaranteed
}
}
Комментарии:
1. Неясно, что вы запрашиваете при редактировании
2. Чтобы все эти похожие классы вели себя одинаково, все они должны реализовывать определенные функции (а именно мои пользовательские события).
3. Просто поместите эти события в свой интерфейс
Ответ №1:
C # позволяет классу как наследовать от базового класса, так и реализовывать интерфейс, так почему бы просто не сделать и то, и другое?
public interface IFoo
{
public void Bar();
public bool Baz();
}
public abstract class BaseFoo : IFoo
{
//fields/properties used in all classes
public void Bar()
{ //Implementation }
public bool Baz()
{ //Implementation }
}
public class DerivedFoo : BaseFoo, IFoo {...}
Ответ №2:
У AllenG есть мой плюс, но поскольку я уже напечатал это, вот более длинная и наглядная демонстрация концепции…
Определите свой интерфейс…
public interface IFoo
{
void DoIt();
void DoItWithoutDefaultBehavior();
}
Определите базовый класс, который реализует интерфейс с некоторым поведением по умолчанию, или, возможно, некоторые методы не имеют поведения по умолчанию…
public abstract class BaseFoo : IFoo
{
public virtual void DoIt()
{
// Base behavior
Console.WriteLine("base");
}
// This one has no base behavior
public abstract void DoItWithoutDefaultBehavior();
}
Некоторые из ваших подклассов могут использовать поведение по умолчанию…
public class DerivedFoo1 : BaseFoo, IFoo
{
// Doesn't override DoIt, takes BaseFoo
public override void DoItWithoutDefaultBehavior()
{
Console.WriteLine("foo1");
}
}
Другие могут добавлять к ним…
public class DerivedFoo2 : BaseFoo, IFoo
{
public override void DoIt()
{
base.DoIt();
// Additional stuff
Console.WriteLine("derived");
}
public override void DoItWithoutDefaultBehavior()
{
Console.WriteLine("foo2");
}
}
Вы можете вызывать методы через класс или интерфейс.
void Main()
{
var foo1 = new DerivedFoo1();
foo1.DoIt();
var foo2 = new DerivedFoo2();
foo2.DoIt();
IFoo foo1AsFoo = new DerivedFoo1();
foo1AsFoo.DoIt();
IFoo foo2AsFoo = new DerivedFoo2();
foo2AsFoo.DoIt();
}
Смотрите также: Сообщение Эрика Липперта, в котором обсуждается, DerivedFoo1
и DerivedFoo2
следует ли повторно указывать, что они реализуют, IFoo
когда BaseFoo
это уже сказано. В моем примере они делают это для того, чтобы быть явными.
РЕДАКТИРОВАТЬ Определенно возможно добавлять события в интерфейс. Я внес следующие изменения в свой пример. Вы могли бы внести аналогичные изменения:
- Чтобы
interface IFoo
добавитьevent EventHandler TheEvent;
- Чтобы
BaseFoo
добавитьpublic event EventHandler TheEvent;
- Чтобы
BaseFoo.DoIt
добавитьif (TheEvent != null)
{
var args = new EventArgs();
TheEvent(this, args);
} - Добавить
public void TheHandler(object sender, EventArgs e)
{
Console.WriteLine("Fired.");
} - Чтобы
Main
добавитьfoo1.TheEvent = TheHandler;
Результат теперь становится
base
Fired.
base
derived
base
base
derived
Комментарии:
1. Я думаю, что это ответ, который я искал. Я подумал, что мне, возможно, придется реализовать интерфейс в базовом классе и каким-то образом перенести это в производный класс. Мне нужно отвернуться от монитора и поразмышлять над этим несколько минут. Похоже, это делает не совсем то, что я хотел.
2. К вашему сведению: я также видел версию AllenG, но не был уверен, что с ней делать. Спасибо за более подробное объяснение.
3. Есть ли способ добавлять СОБЫТИЯ в ваш интерфейс? Я пробовал на своей стороне, но по какой-то причине эти события недоступны или не видны в моем производном классе. Я уверен, что делаю что-то не так.
Ответ №3:
Да, и вы уже ответили сами. Вы будете делать оба:
- Иметь базовый класс с базовой реализацией
- Пусть дочерние классы (или базовый класс, почему бы и нет?) реализуют нужные вам интерфейсы.
Ответ №4:
Вы можете смешивать как интерфейс, так и абстракцию, я думаю, что вы хотите что-то вроде этого
public interface IFoo
{
void ImplementMe();
int ImplementId { get; }
}
public abstract class BaseFoo : IFoo
{
public virtual void ImplementMe()
{
CommonStuff();
}
public abstract int ImplementId { get; }
private void CommonStuff()
{
// ... do stuff ?
}
}
public sealed class FooImplementationA : BaseFoo
{
public override int ImplementId { get { return 0; } }
public override void ImplementMe()
{
MoreStuff();
base.CommonStuff();
}
private void MoreStuff()
{
// ... do more stuff.
}
}
public sealed class FooImplementationB : BaseFoo
{
public override int ImplementId { get { return 1; } }
public override void ImplementMe()
{
DifferentStuff();
base.CommonStuff();
}
private void DifferentStuff()
{
// ... do different stuff.
}
}
но опять же, вам на самом деле не нужен интерфейс, и вы можете просто использовать BaseFoo
абстрактный класс
Ответ №5:
Ключевое слово ‘abstract’ — это то, что вы ищете.
abstract class Base
{
virtual protected void SubclassCanCallAndOptionallyOverride() {}
abstract protected void SubclassMustBeImplement();
}
Для получения более подробной информации: http://msdn.microsoft.com/en-us/library/ms173150.aspx
Комментарии:
1. Почти все, что мне нужно, может быть обработано
interface
, но мне бы очень хотелось, чтобы классы, которые это реализуют,interface
имели в себе некоторые гарантированные пользовательские типы и значения. Можно ли это сделать?