Как бороться с отсутствием множественного наследования в C#

Я работаю над мини-фреймворком для "запускаемых" вещей. (Это эксперименты, тесты, задачи и т. д.)

// Something that "runs" (in some coordinated way) multiple "runnable" things.
interface IRunnableOf where : IRunnable

// Provide base-class functionality for a "runner"
abstract class RunnerBase : IRunnableOf


class SequentialRunner : RunnerBase  // Same interface, different behavior.
class ConcurrentRunner : RunnerBase
// other types of runners.

class ConcurrentBlockRunner : SequentialRunner
class SequentialBlockRunner : ConcurrentRunner

Теперь, как я могу согласовать ConcurrentBlockRunnerи SequentialBlockRunner? Под этим я подразумеваю:

  1. Ссылаться на них по общему предку для использования в коллекции. ( IEnuerableгде T = ??)

  2. Предоставляет дополнительные функциональные возможности базового класса. (Добавить свойство, например).


Я исправил #1, добавив еще один интерфейс, который просто указал параметр типа в IA:

interface IBlockRunner : IRunnableOf { }

И изменил мои ConcurrentBlockRunnerи SequentialBlockRunnerопределения будут следующими:

class ConcurrentBlockRunner : SequentialRunner, IBlockRunner
class SequentialBlockRunner : ConcurrentRunner, IBlockRunner

Поскольку ConcurrentBlockRunnerи SequentialBlockRunnerиспользуют Blockв качестве параметра своего типа, это кажется правильным решением. Тем не менее, я не могу не чувствовать себя «странно» по этому поводу, потому что я только что добавил этот интерфейс.


Для #2 я хочу добавить пару общих данных в ConcurrentBlockRunnerи SequentialBlockRunner. Есть несколько свойств, которые применяются к ним, но не к их единственному общему базовому классу, который полностью находится в RunnerBase.

Впервые при использовании C# я почувствовал, что множественное наследование может помочь.Если бы я мог сделать:

abstract class BlockRunnerBase {
   int Prop1 { get; set; }
   int Prop2 { get; set; }

class ConcurrentBlockRunner : SequentialRunner, BlockRunnerBase
class SequentialBlockRunner : ConcurrentRunner, BlockRunnerBase

Тогда я мог бы просто добавить эти дополнительные свойства в BlockRunnerBase, и все просто заработало бы. Есть ли способ лучше?


Я знаю, что мне немедленно порекомендуют рассмотреть композицию, с которой я начал работать:

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для проксирования событий, а на самом деле обрабатывать их и вызывать собственное событие. Столько работы, чтобы добавить пару свойств...

11
задан John Saunders 12 June 2012 в 00:02
поделиться