Pull to refresh

В дженериках C# мог бы быть полезен “this type”

Reading time2 min
Views3.7K
Разбирая наш код, нашел место, которое явно требовало бы некоторой подчистки. Но чтобы почистить, в языке нужна бы еще фича, которую и хочу обсудить. Я поднимал этот вопрос также и на StackOverflow. Был поддержан авторитетным камрадом.

Возьмем два класса, один наследуют от другого. Базовый класс – дженерик, в котором есть метод, который в производном закрытом типе должен возвращать экземпляр этого самаого закрытого типа.

Например, так (обратите внимание на ??? в тексте):

public class Adapter<T>
{
  public virtual ??? DoSomething()
  {
     ...
  }
}

public class AdaptedString : Adapter<String>
{
  public override AdaptedString DoSomething()
  {
    ...
  }
}


* This source code was highlighted with Source Code Highlighter.


Так сделать нельзя, так как в нет способа сослаться на тип, получающийся при “закрытии” дженерика. Нет такого ключевого слова, которым можно заменить “???”, чтобы указать, что этот метод будет возвращать экземпляр производного закрытого класса.

Вместо этого остается только обходное решение. Надо явным образом передавать тип в базовый класс. Получается явно избыточно:

public class Adapter<TThis,T>
{
  public virtual TThis DoSomething()
  {
    ...
  }
}

public class AdaptedString : Adapter<AdaptedString,String>
{
  public override AdaptedString DoSomething()
  {
    ...
  }
}


* This source code was highlighted with Source Code Highlighter.


А если в базовом классе нужно обращаться к методам экземпляра типа TThis, то приходится добавлять констрейнт. И получается совсем страшно:

public class Adapter<TThis,T>
  where TThis : Adapter<TThis, T>
{
  protected int _field;
  ...
  public bool Compare( TThis obj )
  {
    return _field == obj._field;
  }
}

public class AdaptedString : Adapter<AdaptedString,String>
{
  ...
}


* This source code was highlighted with Source Code Highlighter.


В принципе, это работает. Но выглядит очень непонятно. Каждый раз, когда смотришь на этот код, путаешься, и нужно какой-то время, чтобы разобраться кто есть кто.

Кажется было бы гораздо удобнее, если бы можно было как-то указать, что “TThis” должен быть этим типом. Может быть использовать какое-нибудь ключевое слово. Типа “thistype”, хотя это тоже выглядит страшно. Может быть констрейнт ввести:
where TThis: this type

А то ведь получается, что этот окружной путь позволяет запросто накосячить:

class TypeA : Adapter<TypeA, string>

class TypeB : Adapter<TypeA, string> // Bug!


* This source code was highlighted with Source Code Highlighter.
Tags:
Hubs:
Total votes 10: ↑6 and ↓4+2
Comments19

Articles