如何处理C#中缺少多重继承

时间:2012-06-11 23:20:23

标签: c# oop multiple-inheritance

我正在为“可运行”的东西制作一个迷你框架。 (它们是实验,测试,任务等)。

// 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>

现在,我如何协调ConcurrentBlockRunnerSequentialBlockRunner?我的意思是:

  1. 由共同的祖先引用它们,用于集合。 (IEnuerable<T>其中T = ??)

  2. 提供其他基类功能。 (例如,添加属性)。


  3. 我通过添加另一个只为IA<T>指定类型参数的接口来补救#1:

    interface IBlockRunner : IRunnableOf<Block> { }
    

    并将我的ConcurrentBlockRunnerSequentialBlockRunner定义修改为:

    class ConcurrentBlockRunner : SequentialRunner<Block>, IBlockRunner
    class SequentialBlockRunner : ConcurrentRunner<Block>, IBlockRunner
    

    由于ConcurrentBlockRunnerSequentialBlockRunner都使用Block作为其类型参数,因此这似乎是一个正确的解决方案。但是,我不禁对此感到“怪异”,因为我刚刚在那个界面上添加了。


    对于#2,我想向ConcurrentBlockRunnerSequentialBlockRunner添加几条常用数据。有几个适用于它们的属性,但不适用于它们唯一的公共基类,这在RunnerBase<T>处是一直存在的。

    这是第一次使用C#时,我觉得多重继承会有所帮助。如果我能做到:

    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代理事件,但实际上处理它们,并引发我自己的事件。这么多工作只是为了添加几个属性......

2 个答案:

答案 0 :(得分:2)

Composition over Inheritance,FTW!

更明确:

class SequentialRunner<T> : RunnerBase<T>

应该实现IRunnableOf<T>并代理RunnerBase<T>而不继承它。

class SequentialRunner<T> : IRunnableOf<T>
{
   private readonly RunnerBase<T> _runnerBase;

   ...
}

答案 1 :(得分:1)

即使使用类似属性的元素,也可以使用扩展方法创建mixin-like constructs

我还在C#,NRoles中使用类似特征的构造创建了实验

但是,所有这些都需要非标准编码,并且不适合那些旨在暴露给第三方的API。我认为你应该尝试重新安排你的类,并使用尽可能使用接口的委托组合。