Нет.Учитывая это:
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
, а не только один.Для этого требуется либо метод, либо класс, который возвращает определенный BlockWriter
в зависимости от типа Block
.Это означает проверку типов во время выполнения, что не идеально, но не так уж плохо, если вы храните его в одном месте.
Вот простой пример:
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();
}
}
(A NullBlockWriter
будет просто классом, который ничего не делает, когда вы вызываете его метод Write
.)
Thisпроверка типа не идеальна, но, по крайней мере, это держит ее изолированной в одном классе.Теперь вы можете создать (или внедрить) экземпляр фабрики и вызвать GetBlockWriter
, а остальная часть вашего кода в этом методе все равно не будет «ничего» знать о различных типах Block
или BlockWriter
.
BlockWriter w = new BlockWriter();
станет
BlockWriter w = blockWriterFactory.GetBlockWriter(block);
... и тогда все остальное будет таким же.
Это самый простой возможный заводской пример.Существуют и другие подходы к созданию такой фабрики.Вы можете сохранить все свои реализации в Dictionary<Type, BlockWriter>
и попытаться получить экземпляр, используя block.GetType()
.