我正在为“可运行”的东西开发一个迷你框架。(它们是实验、测试、任务等)
// 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
它们的类型参数,这似乎是一个正确的解决方案。但是,我不禁对此感到“奇怪”,因为好吧,我只是添加了那个界面。
ConcurrentBlockRunner
对于 #2,我想在和中添加几条常见数据SequentialBlockRunner
。有几个属性适用于它们,但不适用于它们唯一的公共基类,一直到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
. 但是,事件处理程序试图将其强制转换为 type BlockRunner
,这当然失败了。那里的解决方案不是使用add
/remove
来代理事件,而是实际处理它们,并引发我自己的事件。这么多工作只是为了添加几个属性......