Как получить доступ к анонимным полям в динамической сборке c? - PullRequest
1 голос
/ 28 апреля 2020

. net Framework 4.7.2 ...

Скомпилированные выражения могут получить доступ к закрытым полям. Когда я использую точно такое же выражение и записываю его в динамическую сборку c, используя CompileToMethod, я получаю System.FieldAccessException при попытке прочитать приватное поле.

Могу ли я что-нибудь сделать, чтобы сборка Dynami c имела те же привилегии доступа, что и скомпилированное выражение? Есть древние знания, которые говорят, что вы не можете. Но я не могу найти ничего похожего на первоисточник этого утверждения. Я не могу поверить, что не существует какой-либо формы атрибутов сборки или разрешений, которые позволили бы получить доступ.

Можно ли это сделать, если вместо этого сохранить сборку? (Запись кэшированных сборок на диск является вероятной особенностью в будущем.)

Приложение сортирует структуры в потоки на языке c computer musi c, определяемом доменом. Сериализация не является опцией (еще один пример динамического c кода в динамических c сборках, который нарушает доступ).

Пример кода:

Лямбда-выражение успешно считывает значение частного поля ComplexStruct (приведено ниже). Если одно и то же выражение отправляется в динамическую сборку c с использованием CompileToMethod, оно завершается с ошибкой доступа.

    ComplexStruct s = new ComplexStruct();

    s.String1 = "abc";

    // Pick a private field (one of the backing fields for a property)
    FieldInfo fieldInfo = typeof(ComplexStruct).GetFields(BindingFlags.NonPublic | BindingFlags.Instance)[0];

    var structArgument = Expression.Parameter(typeof(ComplexStruct));

    var lambda = Expression.Lambda<Func<ComplexStruct,String>>(
        Expression.Field(structArgument, fieldInfo), // return the value of the private field.
        structArgument);
    Func<ComplexStruct,String> fn = lambda.Compile();

    String result = fn(s);
    Assert.AreEqual(structArgument.String1, result);

Структура с закрытыми полями:

// (Complex compared to simple struct where all fields 
// are public or the struct is unmanaged in case you were wondering)
public struct ComplexStruct : IEquatable<ComplexStruct>
{

    public String String1 { get; set; } // the backing field for this property gets read.
    public String String2 { get; set; }
    public String String3 { get;  }

    public ComplexStruct(String v1, String v2)
    {
        String1 = v1;
        String2 = v2;
    }

    public bool Equals(ComplexStruct other)
    {
        return String1 == other.String1 && String2 == other.String2;
    }
}

Создание сборка:

    AppDomain myAppDomain = Thread.GetDomain();
    AssemblyName myAsmName = new AssemblyName();
    myAsmName.Name = "DynamicAssembly";

    this.saveAssembly = ServiceBase.DEBUG;

    assemblyBuilder = myAppDomain.DefineDynamicAssembly(
                         myAsmName,
                         saveAssembly? AssemblyBuilderAccess.RunAndSave: AssemblyBuilderAccess.RunAndCollect);

1 Ответ

1 голос
/ 01 мая 2020

После просмотра. net источников кажется вполне уверенным, что Assembly не сможет обойти проверки доступа к полям.

thehennyy указал на черный ход, который используют выражения Linq. Конструкторы DynamicMethod предоставляют параметр skipVisibility, который позволяет генерировать IL, который может обращаться к неопубликованным полям и методам c. Но невозможно объединить DynamicMethod s с сборками Dynami c или отправить их в сохраненную сборку.

Учитывая ограничения DynamicMethod s, похоже, нет никаких причин для предпочитайте их выражениям Linq, учитывая, что API выражений Linq бесконечно проще использовать эти API IL.Emit.

В конце я использовал обратные вызовы для шаблонных классов, которые генерируют делегаты структуризации сериализации, создаваемые выражениями Linq в stati c конструкторы.

Если вы следуете по одному и тому же пути, вы можете захотеть взглянуть на «неуправляемые» структуры, представленные в C# 7.2, которые позволяют оптимизировать сериализацию структур, состоящих полностью из ValueType участники. Учитывая, что String s являются ссылочными классами, это обычно имеет ограниченное значение. Но, учитывая, что я пытаюсь написать сериализаторы без распределения, они были полезны для моих целей.

...