没有。鉴于此:
public void WriteBlocks(List<Block> blocks)
编译器对列表中每个项目的唯一了解是它是Block。这就是它应该知道的一切。这就是使多态性成为可能的原因。可以有任意数量的类继承自 Block,但在这种情况下,这些区别并不重要。
但如果编译器只知道每个项目都是Block,它就无法知道任何单个项目是否可能是TableBlock、TextBlock 或其他继承类型。如果在编译时它不知道运行时类型是什么,它甚至无法知道该特定类型是否存在重载。
假设您尝试执行的操作可以编译,因为您对从Block 继承的每种类型都有一个重载。如果您添加了一个新类型 - class PurpleBlock : Block - 并且它没有重载,将会或应该发生什么?这是否应该仅仅因为您添加了新类型而不再编译?
如果调用 WriteBlocks 的方法知道Block 在列表中的类型,那么它可以提供该信息:
public void WriteBlocks<TBlock>(List<TBlock> blocks) where TBlock : Block
现在您可以调用WriteBlock<TextBlock>(listOfTextBlocks),编译器将知道列表中的每一项都是TextBlock,而不仅仅是Block。
因此,BlockWriter 也必须是通用的,以便您可以对不同类型的Block 有不同的实现。注入它可能更有意义。无论哪种方式,您都可能认为您已经“解决了”问题。如果调用WriteBlocks 的类“知道”Block 的类型,那么该方法确定要使用的BlockWriter 的类型可能更有意义。
正如您在评论中提到的,该列表可能包括不同类型的 Block,而不仅仅是一种。这需要根据Block 的类型返回特定BlockWriter 的方法或类。这意味着运行时类型检查,这并不理想,但如果将它保存在一个地方也不算太糟糕。
这是一个简单的例子:
public class BlockWriterFactory
{
public BlockWriter GetBlockWriter(Block block)
{
if (block is TextBlock)
return new TextBlockWriter();
if (block is TableBlock)
return new TableBlockWriter();
if (block is ListBlock)
return new ListBlockWriter();
// this could be a "null" class or some fallback
// default implementation. You could also choose to
// throw an exception.
return new NullBlockWriter();
}
}
(当您调用 Write 方法时,NullBlockWriter 将只是一个不执行任何操作的类。)
这种类型检查并不理想,但至少可以将其隔离到一个类中。现在您可以创建(或注入)工厂的一个实例,并调用GetBlockWriter,并且该方法中的其余代码仍然不会“知道”关于Block 或BlockWriter 的不同类型的任何信息。
BlockWriter w = new BlockWriter();
会变成
BlockWriter w = blockWriterFactory.GetBlockWriter(block);
...然后其余的还是一样的。
这是最简单的工厂示例。还有其他方法可以创建这样的工厂。您可以将所有实现存储在 Dictionary<Type, BlockWriter> 中,并尝试使用 block.GetType() 检索实例。