Я работаю над мини-картой для "управляемых" вещей. (Это эксперименты, тесты, задания и т.д.)
// Something that "runs" (in some coordinated way) multiple "runnable" things.
interface IRunnableOf<T> where : IRunnable
// Provide base-class functionality for a "runner"
abstract class RunnerBase<T> : IRunnableOf<T>
class SequentialRunner<T> : RunnerBase<T> // Same interface, different behavior.
class ConcurrentRunner<T> : RunnerBase<T>
// other types of runners.
class ConcurrentBlockRunner : SequentialRunner<Block>
class SequentialBlockRunner : ConcurrentRunner<Block>
Теперь, как я могу примирить ConcurrentBlockRunner
и SequentialBlockRunner
? Под этим я подразумеваю:
-
Обратитесь к ним общим предком, для использования в коллекции. (
IEnuerable<T>
где T =??) -
Предоставить дополнительную функциональность базового класса. (Добавьте свойство, например).
Я исправил # 1, добавив еще один интерфейс, который только что задал параметр типа IA<T>
:
interface IBlockRunner : IRunnableOf<Block> { }
И изменили мои определения ConcurrentBlockRunner
и SequentialBlockRunner
:
class ConcurrentBlockRunner : SequentialRunner<Block>, IBlockRunner
class SequentialBlockRunner : ConcurrentRunner<Block>, IBlockRunner
Так как ConcurrentBlockRunner
и SequentialBlockRunner
используют Block
для своего параметра типа, это кажется правильным решением. Однако я не могу не чувствовать себя "странно", потому что хорошо, я просто применил этот интерфейс.
Для # 2, я хочу добавить пару общих данных в ConcurrentBlockRunner
и SequentialBlockRunner
. Существует несколько свойств, которые применяются к ним, но не только к их единственному базовому классу, который находится на уровне RunnerBase<T>
.
Это первый раз, когда я использую С#, который, как я понял, поможет множественному наследованию. Если бы я мог:
abstract class BlockRunnerBase {
int Prop1 { get; set; }
int Prop2 { get; set; }
class ConcurrentBlockRunner : SequentialRunner<Block>, BlockRunnerBase
class SequentialBlockRunner : ConcurrentRunner<Block>, BlockRunnerBase
Тогда я мог бы просто добавить эти дополнительные свойства в BlockRunnerBase, и все будет работать. Есть ли лучший способ?
Я знаю, что мне будет предложено немедленно рассмотреть composition, с которым я начал работать:
class BlockRunner : IBlockRunner {
IBlockRunner _member;
int Prop1 { get; set; } // Wish I could put these in some base class
int Prop2 { get; set; }
// Lots of proxy calls, and proxy events into _member
void Method() { _member.Method(); }
event SomeEvent
{
add { _member.SomeEvent += value; }
remove { _member.SomeEvent -= value; }
}
}
Проблема, с которой я столкнулась (заставив меня написать этот вопрос), заключалась в том, что как только вы сочиняете, вы теряете совместимость типов. В моем случае _member запускал событие, поэтому параметр sender
имел тип SequentialBlockRunner
. Тем не менее, обработчик события пытался наложить его на тип BlockRunner
, который, конечно, не удался. Решение не использует add
/remove
для прокси-событий событий, но на самом деле их обрабатывает и вызывает собственное событие. Так много работы, чтобы добавить пару свойств...