Непростая задача на generic'и
От: SergASh  
Дата: 29.10.10 08:52
Оценка:
Привет всем!

Есть набор интерфейсов
  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
  {
  }


Хочется написать конфигуратор в fluent стиле, который бы хранил ассоциации между интерфейсами, например чтобы это выглядело так

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(); // Откуда взять тип пред- предыдущего узла?
}


Непонятно как запоминать в IConfigBuilder'е типы всех ранее использованных узлов. То есть как объявлять метод Up()? Тут вспоминаются списки типов по Александреску. Мржет можно что-то подобное сделать в дотнете?

Спасибо.
Re: Непростая задача на generic'и
От: k.o. Россия  
Дата: 29.10.10 10:14
Оценка: 6 (1)
Здравствуйте, SergASh, Вы писали:

SAS>Привет всем!


SAS>Непонятно как запоминать в IConfigBuilder'е типы всех ранее использованных узлов. То есть как объявлять метод Up()? Тут вспоминаются списки типов по Александреску. Мржет можно что-то подобное сделать в дотнете?


так подойдет?

public interface IConfigBuilder<P, T>
{
  IConfigBuilder<IConfigBuilder<P, T>, C> Join<C>( Expression<Func<T, C>> expression );
  P Up();
}

public interface IConfigBuilder<T> : IConfigBuilder<IConfigBuilder<T>, T>
{
}


IConfigBuilder<T> используется как самый "верхний" конфигуратор:

public static class Configurator
{
    public static IConfigBuilder<IConfigBuilder<T>, T> Root<T>()
    {
        return new RootConfigBuilder<T>();
    }
}

class RootConfigBuilder<T> : ConfigBuilder<IConfigBuilder<T>, T>, IConfigBuilder<T>
{
    public RootConfigBuilder()
        : base(() => this)
    {
    }
}

class ConfigBuilder<P, T> : IConfigBuilder<P, T>
{
    private Func<P> parent;

    public ConfigBuilder(Func<P> parent)
    {
        this.parent = parent;
    }

    public IConfigBuilder<IConfigBuilder<P, T>, C> Join<C>(Expression<Func<T, C>> expression)
    {
        return new ConfigBuilder<IConfigBuilder<P, T>, C>(() => this);
    }

    public P Up()
    {
        return this.parent();
    }
}
Re[2]: Непростая задача на generic'и
От: SergASh  
Дата: 29.10.10 20:46
Оценка: +1
Здравствуйте, k.o., Вы писали:

KO>так подойдет?


Да, мегаспасибо за идею. Интересовала именно декларация, ее реализовать не проблема.

Кстати, не советйуте, пожалуйста, никому писать base( () => this ). Это естественно не работает, при вызове делегат вернет null.

СПАСИБО!
Re[3]: Непростая задача на generic'и
От: samius Япония http://sams-tricks.blogspot.com
Дата: 30.10.10 05:37
Оценка:
Здравствуйте, SergASh, Вы писали:

SAS>Кстати, не советйуте, пожалуйста, никому писать base( () => this ). Это естественно не работает, при вызове делегат вернет null.


Если быть точнее, то до вызова не дойдет.

error CS0027: Keyword 'this' is not available in the current context

Re[4]: Непростая задача на generic'и
От: SergASh  
Дата: 30.10.10 07:50
Оценка:
Здравствуйте, samius, Вы писали:

S>Если быть точнее, то до вызова не дойдет.

S>

S>error CS0027: Keyword 'this' is not available in the current context


Какая версия компилятора? На this в лямбде C# 3 не ругается.
Re[3]: Непростая задача на generic'и
От: k.o. Россия  
Дата: 30.10.10 08:56
Оценка:
Здравствуйте, SergASh, Вы писали:

SAS>Здравствуйте, k.o., Вы писали:


SAS>Кстати, не советйуте, пожалуйста, никому писать base( () => this ). Это естественно не работает, при вызове делегат вернет null.


Да, это был просто способ побыстрее получить что-то компилирующееся и даже почти работающее

SAS>СПАСИБО!
Re[5]: Непростая задача на generic'и
От: hardcase Пират http://nemerle.org
Дата: 30.10.10 10:07
Оценка:
Здравствуйте, SergASh, Вы писали:

SAS>Здравствуйте, samius, Вы писали:


S>>Если быть точнее, то до вызова не дойдет.

S>>

S>>error CS0027: Keyword 'this' is not available in the current context


SAS>Какая версия компилятора? На this в лямбде C# 3 не ругается.


Нельзя передавать куда либо лямбды с захваченным this до вызова конструктора базового типа.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[6]: Непростая задача на generic'и
От: SergASh  
Дата: 31.10.10 07:36
Оценка: 18 (1)
Здравствуйте, hardcase, Вы писали:

H>Нельзя передавать куда либо лямбды с захваченным this до вызова конструктора базового типа.


Неправильно. Передавать можно и компилятор не возражает, просто это не приводит к ожидаемому результату.

Вот вне лямбды выражение содержать this не может, такое компилятор не пропустит

    class Base2
    {
      public Base2( Derived2 self )
      {
        Self = self;
      }
      public Derived2 Self;
    }
    class Derived2 : Base2
    {
      public Derived2() 
        : base( AnyMethod( this ) )
      { }

      static Derived2 AnyMethod( Derived2 me )
      {
        return me;
      }
    }
Re[7]: Непростая задача на generic'и
От: hardcase Пират http://nemerle.org
Дата: 31.10.10 08:29
Оценка:
Здравствуйте, SergASh, Вы писали:

SAS>Здравствуйте, hardcase, Вы писали:


H>>Нельзя передавать куда либо лямбды с захваченным this до вызова конструктора базового типа.


SAS>Неправильно. Передавать можно и компилятор не возражает, просто это не приводит к ожидаемому результату.

SAS>

Кошмар
/* иЗвиНите зА неРовнЫй поЧерК */
Re[5]: Непростая задача на generic'и
От: nikov США http://www.linkedin.com/in/nikov
Дата: 01.11.10 01:02
Оценка:
Здравствуйте, SergASh, Вы писали:

SAS>Какая версия компилятора? На this в лямбде C# 3 не ругается.


Это был баг в C# 3.0 (такой код не должен компилироваться по спецификации, и он порождал неверифицируемый IL). В C# 4.0 его исправили, теперь это не компилируется.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.