Доброго вечера всем!
Сегодня наконец то нашли применение в проекте с работы для 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 ==========
запостил в
багрекер. Уж извините что и здесь отписался,
но очень надо.. Может здесь кто то имеет предположения в чем прикол?
Здравствуйте, 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.
Здравствуйте, 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.