Боюсь, C# генерики просто так не работают. Здесь нет утки, и вы не получаете различного типа generi c для каждого аргумента типа. Все разрешение типов происходит во время компиляции и не заботится о фактическом типе аргумента типа. Чтобы получить разрешение типа во время выполнения, вам нужно использовать dynamic
со всеми его трудностями.
Альтернативы во многом зависят от ваших требований. Например, если у вас есть полный контроль над типами, которые можно использовать в методах Contains
, вы можете выполнить собственное разрешение типов:
if (box is Box2 box2 && line is Line2 line2) return Contains(box2, line2);
else if (box is Box3 box3 && line is Line3 line3) return Contains(box3, line3);
Это, вероятно, fast что вы можете сделать (кроме того, что у вас есть конкретная c реализация для каждого случая в первую очередь). Если вы ищете что-то с меньшим обслуживанием, вы можете использовать делегаты:
static bool ContainsImpl<TB, TL, TP>(List<TB> boxes, TL line, Func<TB, TL, bool> intersect)
{
DoAllTheStuff();
if (intersect(box, line)) ...
}
public static Contains(List<Box2> boxes, Line2 line)=> ContainsImpl(boxes, line, Intersect);
public static Contains(List<Box3> boxes, Line3 line)=> ContainsImpl(boxes, line, Intersect);
Метод generi c содержит общий логический c для выполнения Contains
и делегирует все указать c материал, основанный на фактических типах (любой пользователь вашей библиотеки будет использовать не * generi c методы). Основное преимущество заключается в том, что вы получаете полную проверку типов таким образом - вы не можете случайно забыть случай сопоставления с образцом для нового добавленного вами типа. Это, вероятно, не стоит накладных расходов делегата, учитывая, насколько простой метод пересечения. Вам нужно подумать о пользователях вашей библиотеки.
В некоторых случаях может быть целесообразно инвертировать все и использовать модель вытягивания (например, через IEnumerable<TB>
) вместо нажатия. Но опять же, все это вызов, который вы должны сделать исходя из своих реальных требований. И, конечно, вы всегда можете использовать генерацию кода - иногда просто нет хорошего способа представить шаблон в C#, и такие вещи, как шаблоны T4, могут значительно помочь.
В общем, C# дженерики, ну, дженерики c. Если ограничения типа c недостаточно для того, что нужно сделать Contains
, нет смысла делать его универсальным c. Вы все еще можете использовать его, чтобы избежать ненужного повторения кода, он отлично подходит для сгенерированных типов во время выполнения и применения делегатов, но он не может сделать больше, чем позволяют ограничения типов без явного приведения (или dynamic
). Это не шаблоны C ++, и они не меняют C# на Python или Scala.