Списки типов в обобщениях C #: это возможно? - PullRequest
1 голос
/ 29 октября 2010

При условии наличия следующих интерфейсов

public interface IRoot
{
  IChildA ChildA { get; }
  IChildB ChildB { get; }
}  
public interface IChildA
{
  IGrandChildA GrandChildA { get; }
  IGrandChildB GrandChildB { get; }
}
public interface IChildB
{
  IGrandChildC GrandChildC { get; }
}
public interface IGrandChildA
{
}
public interface IGrandChildB
{
}
public interface IGrandChildC
{
}

Я бы хотел написать «конфигуратор» в свободном стиле, чтобы сохранить ассоциации интерфейсов. Все должно выглядеть так:

private static void Test()
{
  Configurator.Root<IRoot>()
    .Join( _ => _.ChildA )
    .Join( _ => _.GrandChildA )
    .Up()
    .Join( _ => _.GrandChildB )
    .Up()
    .Up()
    .Join( _ => _.ChildB );
}

Требуется разрешить произвольный уровень вложенности пар Join / Up. Вот моя попытка объявить такой конфигуратор.

public static class Configurator
{
  public static IConfigBuilder<T, T> Root<T>()
  {
    return null;
  }
}
public interface IConfigBuilder<P, T>
{
  IConfigBuilder<T, C> Join<C>( Expression<Func<T, C>> expression );
  IConfigBuilder<???, P> Up(); // This is the problem. How can I get grand-parent type?
}

Мне неясно, как я мог запомнить все предыдущие типы узлов. Другими словами, как объявить метод Up()? Это напоминает мне старые добрые списки типов Александреску в C ++. Есть ли способ добиться того же в .net?

1 Ответ

2 голосов
/ 29 октября 2010

Вам понадобится как минимум два интерфейса; и вместо того, чтобы возвращать IConfigBuilder<...> для Up, доверяйте создаваемому коду, чтобы знать, что он создал:

public interface IConfigBuilder<T>
{
    IConfigBuilder<IConfigBuilder<T>, C> Join<C>(Expression<Func<T, C>> expression);
}
public interface IConfigBuilder<P, T> : IConfigBuilder<T>
{
    P Up(); // This is the problem. How can I get grand-parent type?
    new IConfigBuilder<IConfigBuilder<P, T>, C> Join<C>(Expression<Func<T, C>> expression);
}
...