Проверьте, является ли динамическая сборка .NET временной или постоянной

#c# #.net #reflection #reflection.emit

#c# #.net #отражение #reflection.emit

Вопрос:

Когда система.Reflection.Emit.AssemblyBuilder создан, его можно сохранить (инициализировать с помощью AssemblyBuilderAccess .Сохранить и тому подобное) или переходный (AssemblyBuilderAccess.Запустите o и аналогичные). Я собираюсь создать ModuleBuilder для assembly builder, который у меня есть в качестве входных данных. Но постоянный модуль не может быть создан для переходной сборки, поэтому я должен проверить статус сборки перед созданием модуля. Как я могу это сделать? Фрагмент является:

 public ModuleBuilder Handle(AssemblyBuilder assembly, string name)
{
    if (assembly.IsPersisted) // IsPersisted is a kind of property I'm looking for
    {
        return assembly.DefineDynamicModule(name, name   ".dll");
    }
    else
    {
        return assembly.DefineDynamicModule(name);
    }
}
  

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

Комментарии:

1. Просто предположение, но что делает сборка. Кодовая база дает вам. IIRC это путь к файлу exe или dll на диске. Если она не сохраняется, это может дать подсказку.

2. Почему вы создаете модули отдельно от сборок? Вы почти всегда хотите иметь ровно один модуль в каждой сборке.

3. @simon в rcl: интересная идея, но в обоих случаях я получаю исключение NotSupportedException.

4. Как насчет сборки. Местоположение? Извиняюсь, это было свойство, которое я имел в виду; не уверен, почему я придумал CodeBase. Если это не поможет, возможно, стоит проверить кодовую базу для вашего базового exe-файла: если это не возвращает исключение, то, возможно, вы могли бы использовать этот факт: Exception = not persisted?

5. @svick: из-за SRP. С одной стороны, у меня есть множество расширений для создания сборок (пусть это будет N), которые можно расширить. С другой стороны — множество процедур создания модулей (M). Передавая AssemblyBuilder этим подпрограммам, я могу смешивать различные стратегии эмиссии. Если я соберу их вместе, я получу сложность N * M вместо N M.

Ответ №1:

Только что столкнулся с этой точной ситуацией — единственный реальный способ справиться с этим, не передавая переменную состояния, указывающую, должна ли сборка быть постоянной, это:

 try
{
    return assembly.DefineDynamicModule(name, name   ".dll");
}
catch(NotSupportedException)
{
    return assembly.DefineDynamicModule(name);
}
  

Не очень — но реальной альтернативы нет.

Ответ №2:

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

 if (assembly.IsDynamic)
{
        Type assemblyType = assembly.GetType();

        Type assemblyBuilderDataType = Assembly.GetAssembly(assemblyType)
                .GetType("System.Reflection.Emit.AssemblyBuilderData");

        object assemblyBuilderData = assemblyType
                .GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
                .Single(fi => fi.FieldType == assemblyBuilderDataType)
                .GetValue(assembly);

        object assemblyBuilderAccess = assemblyBuilderDataType
                .GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
                .Single(fi => fi.FieldType == typeof(AssemblyBuilderAccess))
                .GetValue(assemblyBuilderData);

        switch (assemblyBuilderAccess)
        {
                …
        }
}