Как получить доступ к анонимным полям в динамической сборке?

.net Framework 4.7.2...

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

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

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

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

Пример кода:

Лямбда-выражение успешно считывает значение частного поля ComplexStruct (приведено ниже). Если то же выражение передается в динамическую сборку с помощью 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);

2 ответа

Смотрите мой ответ на этот вопрос для более подробной информации о недокументированныхIgnoreAccessCheckToAttributeкоторый делает то, что вы, вероятно, хотите.

Вот пример кода:

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

      var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(name),
                                                   AssemblyBuilderAccess.RunAndCollect);

var assmemblyNames = typesToAccess.Where(t => t is not null)
    .Select(t => t!.Assembly.FullName.Split(',').First()) // Extract the name from fullName
    .Distinct().ToList();

var ignoreAccessCtor = typeof(IgnoresAccessChecksToAttribute)
                              .GetConstructor(new Type[] { typeof(string) });

foreach (var refName in assemblyNames)
{
      var builder = new CustomAttributeBuilder(ignoreAccessCtor, new object[] { refName });
      assemblyBuilder.SetCustomAttribute(builder);
}

Изучив источники.net, можно с уверенностью сказать, что нет возможности Assembly для обхода проверок доступа к полю.

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

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

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

Если вы идете по тому же пути, вы можете посмотреть на "неуправляемые" структуры, представленные в C# 7.2, которые позволяют оптимизировать сериализацию структур, полностью состоящих из ValueTypeчлены. При условииStrings - ссылочные классы, которые обычно имеют ограниченную ценность. Но, учитывая, что я пытаюсь написать сериализаторы без выделения памяти, они были полезны для моих целей.

Другие вопросы по тегам