[n1] Проблема с вызовом сериализации изнутри компилятора
От: BogdanMart Украина  
Дата: 04.01.11 21:40
Оценка:
Доброго вечера всем!

Сегодня наконец то нашли применение в проекте с работы для Nemerle, которое будет в соей нише, даже солюшен отдельный -- не будет желания переписать все с C# да и модуль который пишется почти с нуля и независимо. + Кодогенерация.

Суть такова. У нас есть распределенное приложение (Сервер и много клиентов и агентов). Сервер подключается к СУБД а клиенты к серверу. Клиенты работают уже не с таблицам и с персистентными данными, обычно деревья(Нода содержит список других нодов и спусок свойств/атрибутов текущей ноды, причем атрибуты в каждой разные, но каждый имеет какое то значение примитивного типа).

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

Придумали следующие:
Генерировать макросом уровня сборки объектную модель для базы те немерла генрит объект Комп с пропортой Процессор -- обект в коорого есть пропорты частота/нагрузка/температура), потом в железа пропорта оперативка -- объект в которого есть пропорты объем/занято..

Но столкнулись с внутренним ограничением компилятора.... Точнее даже не компилятора а скорее всего дотнета, не знаю где но где то ncc конфликтует с дотнтом, может кто то игрался с настройками беопастности и знает в чем дело.

В общем ошибка сводиться к тому, что при попытке десериализировать любой объект выскакивает исключение в котором говорится, что не удалось загрузить сборку(и имя сборки) это сборка в которой располагается класс сериализированого объекта. причем даже если это текущая сборка (тоесть уже загруженная)

Вот код приводящий к багу
  [Nemerle.MacroUsage (Nemerle.MacroPhase.WithTypedMembers, Nemerle.MacroTargets.Assembly)]
  public macro BuggyMacro()
  {
    def typer = Nemerle.Macros.ImplicitCTX();
    when((!typer.Manager.IsIntelliSenseMode))//&&Connector.IsConnected)
    {
      BuggyMacroImpl.Exec(typer);
    }    
  }
  
  internal module BuggyMacroImpl
  {
    internal Exec(_:Typer):void
    {
      try
      {
        _ = System.Diagnostics.Debugger.Launch();
        def c = C();
        
        def ser = BinaryFormatter();
        def ms = MemoryStream();
        ser.Serialize(ms, c);
        _ = ms.Seek(0, SeekOrigin.Begin);
        def c2 = ser.Deserialize(ms);   // Exception: Cannot find assembly "MacroLibrary1, Version=1.0.0.0...
        ignore(c2);
      }
      catch
      {
        | e => Message.Error(e.Message);
      }
    }
  }
  
  [Serializable]
  internal class C
  {
    public a : int = Random().Next();
  }


и вывод компиляятора:
------ Build started: Project: MacroLibrary1, Configuration: Debug Any CPU ------
Build succeeded -- 0 warnings. Build took: 00:00:00.1099386.
------ Build started: Project: ClassLibrary1, Configuration: Debug Any CPU ------
C:\Users\winnie\Documents\Visual Studio 2008\Projects\Nemerle Serialization Bug\ClassLibrary1\Class1.n(10,12):Error: 
Не удалось найти сборку "MacroLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null".
Build failed -- 1 errors, 0 warnings. Build took: 00:00:00.9181763.
========== Build: 1 succeeded or up-to-date, 1 failed, 0 skipped ==========


запостил в багрекер. Уж извините что и здесь отписался, но очень надо.. Может здесь кто то имеет предположения в чем прикол?
Re: [n1] Проблема с вызовом сериализации изнутри компилятора
От: VladD2 Российская Империя www.nemerle.org
Дата: 05.01.11 02:07
Оценка: 3 (1) +1
Здравствуйте, BogdanMart, Вы писали:

BM>Но столкнулись с внутренним ограничением компилятора.... Точнее даже не компилятора а скорее всего дотнета, не знаю где но где то ncc конфликтует с дотнтом, может кто то игрался с настройками беопастности и знает в чем дело.


BM>В общем ошибка сводиться к тому, что при попытке десериализировать любой объект выскакивает исключение в котором говорится, что не удалось загрузить сборку(и имя сборки) это сборка в которой располагается класс сериализированого объекта. причем даже если это текущая сборка (тоесть уже загруженная)


Поковырялся... Дело видимо в системе разрешения (resolving) сборок. Чтобы System.Reflection генерировал сборки поляки очень много плясали с бубном. Видимо или накосячили чего-то, или это побочный эффект от их плясок.

Обойти можно добавив подобный обработчик в сборку с макросами:
      System.AppDomain.CurrentDomain.AssemblyResolve += 
        fun (_, arg)
        {
          def asm = typeof(C).Assembly;
          
          if (arg.Name == asm.FullName)
            asm
          else
            null
        };


Его надо или засунуть в статический конструктор одного из классов, но тогда не факт, что не придется резолвить и другие сборки (надо пробовать), или непосредственно перед кодом сериализации. При этом его желательно отключить. Для этого лучше явно создать делегат, поместить его в локальную переменную и отписаться после завершения работы кода сериализации.

BM>запостил в багрекер. Уж извините что и здесь отписался, но очень надо.. Может здесь кто то имеет предположения в чем прикол?


Да ничего страшного. Все нормально. Главное чтобы был создан issues.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [n1] Проблема с вызовом сериализации изнутри компилят
От: BogdanMart Украина  
Дата: 05.01.11 08:41
Оценка:
Здравствуйте, VladD2, Вы писали:

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


VD>Поковырялся... Дело видимо в системе разрешения (resolving) сборок. Чтобы System.Reflection генерировал сборки поляки очень много плясали с бубном. Видимо или накосячили чего-то, или это побочный эффект от их плясок.


Спасибо огромное!! Помогло.

Только я использовал:

       System.AppDomain.CurrentDomain.AssemblyResolve += 
        fun (v, arg)
        {
          def dom = v :> AppDomain;
          def asm = dom.GetAssemblies().Find(a=> a.FullName==arg.Name);
          match(asm)
          {
            | Some(a) => a
            | _ => null
          }
        };


Просто у нас много типов из разных сборок, а так оно все находит..

VD>При этом его желательно отключить. Для этого лучше явно создать делегат, поместить его в локальную переменную и отписаться после завершения работы кода сериализации.


Вроде бы и так хорошо работает, без отписки, хотя на всякий случай отпишусь когда буду выходить из макроса. Дело в том, что код десериализации выскакивает повсеместно при общении с сервером через .Net Remouting.
Re[3]: [n1] Проблема с вызовом сериализации изнутри компилят
От: VladD2 Российская Империя www.nemerle.org
Дата: 05.01.11 14:23
Оценка:
Здравствуйте, BogdanMart, Вы писали:

BM>Вроде бы и так хорошо работает, без отписки, хотя на всякий случай отпишусь когда буду выходить из макроса. Дело в том, что код десериализации выскакивает повсеместно при общении с сервером через .Net Remouting.


Значит нужно подписываться в статическом конструкторе, как я говорил ранее.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.