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

// 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?我的意思是:
  • 由共同祖先引用它们,以用于集合中。 (IEnuerable<T>其中T = ??)
  • 提供附加的基类功能。 (例如,添加一个属性)。


  • 我通过向IA<T>添加刚刚指定类型参数的另一个接口(interface)来纠正#1:
    interface IBlockRunner : IRunnableOf<Block> { }
    

    并将我的ConcurrentBlockRunnerSequentialBlockRunner定义修改为:
    class ConcurrentBlockRunner : SequentialRunner<Block>, IBlockRunner
    class SequentialBlockRunner : ConcurrentRunner<Block>, IBlockRunner
    

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

    对于#2,我想在ConcurrentBlockRunnerSequentialBlockRunner中添加几个通用数据。有几个属性适用于它们,但不适用于它们唯一的公共(public)基类,这些属性一直存在于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代理事件,而是实际处理它们并引发我自己的事件。要做很多工作只是添加几个属性...

    最佳答案

    Composition over Inheritance,FTW!

    更明确地说:

    class SequentialRunner<T> : RunnerBase<T>
    

    应该实现IRunnableOf<T>并代理RunnerBase<T>而不继承它。
    class SequentialRunner<T> : IRunnableOf<T>
    {
       private readonly RunnerBase<T> _runnerBase;
    
       ...
    }
    

    关于c# - 如何处理C#中缺少多重继承的问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10988695/

    10-12 17:18