Общий тип, указанный наследниками - PullRequest
0 голосов
/ 19 мая 2018

Я не думаю, что то, что я хочу, возможно, но я надеюсь, что кто-то может это проверить и, возможно, объяснить, почему это невозможно.

У нас есть наследование Bar<T>, для которого мы не можем коснуться источникакод Bar<T>

abstract class Foo<T> : Bar<T>

Мы предлагаем Foo<T> для реализации третьей стороной, и мы также хотим диктовать, что любой класс, наследуемый от Foo<T>, является указанным типом для T.Конечно, это может быть сделано вручную третьей стороной, например

class Fizz : Foo<Fizz>

Однако, я считаю повторение Fizz громоздким и безобразным.Возможно ли Foo<T> автоматически использовать Fizz в качестве указанного типа для T?Другими словами, возможно ли позволить Foo<T> реализовывать что-то по этим направлениям

abstract class Foo : Bar<T>
    where T : "Whatever class inherits from Foo"

... что я не считаю возможным, потому что я не могу найти подходящее ограничение универсального типа.Можно ли сделать что-то вроде этого вместо

[SomeBlackMagic("Dear compiler, T is whatever inherits from Foo.")]
abstract class Foo : Bar<T>

... так, чтобы реализация Fizz могла просто быть

class Fizz : Foo

Ответы [ 4 ]

0 голосов
/ 22 мая 2018
abstract class Foo<T> : Bar<T>
    where T : Foo<T>
{ /* ... */ }

class Fizz : Foo<Fizz>
{ /* ... */ }

Я знаю, что это не то, что вы ищете, но это лучший выбор.

0 голосов
/ 19 мая 2018

Это то, что известно как Любопытно повторяющийся шаблон .К сожалению, большинство строго типизированных языков не имеют возможности устранить этот запах кода.C # не может улучшить это.

Вы можете прибегнуть к проверкам во время выполнения, но за счет проверки во время компиляции.Кроме того, вы не сможете использовать тип в своем интерфейсе класса.Например, вы не сможете сделать что-то вроде abstract class Foo<T> { public T Bar() { ... } }, потому что компилятор не будет знать T.

0 голосов
/ 19 мая 2018

Мы также хотим продиктовать, что любой класс, наследуемый от Foo, является указанным типом для T.

Это требование может быть реализовано как пользовательский анализатор Roslyn.

Хотя этот фрагмент abstract class Foo : Bar<T>, к сожалению, невозможен, причина того, что универсальный параметр T должен быть закрыт каким-либо типом, или Foo также должен быть универсальным.

0 голосов
/ 19 мая 2018

Возможно, это не то, что вы искали, но рассматривали ли вы вопрос о внедрении интерфейса на Foo<T>, чтобы вы всегда могли быть уверены, каким будет тип T?

public class Bar<T>
{}

public interface IDev
{}

public abstract class Foo<T> : Bar<T> where T : IDev
{}

public class Fizz : Foo<Fizz>, IDev
{}

дать вам некоторый контроль над передаваемым универсальным объектом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...