Как получить доступ к анонимным полям в динамической сборке?
.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, который может обращаться к закрытым полям и методам. Но нет возможности интегрироватьDynamicMethod
s с помощью динамических сборок или передать их в сохраненную сборку.
Учитывая ограничения DynamicMethod
s, похоже, нет причин предпочитать их выражениям Linq, учитывая, что API-интерфейсы Linq Expression бесконечно проще использовать эти API-интерфейсы IL.Emit.
В конце концов, я использовал выноски для шаблонных классов, которые генерируют делегаты сериализации структур, создаваемые выражениями Linq в статических конструкторах.
Если вы идете по тому же пути, вы можете посмотреть на "неуправляемые" структуры, представленные в C# 7.2, которые позволяют оптимизировать сериализацию структур, полностью состоящих из ValueType
члены. При условииString
s - ссылочные классы, которые обычно имеют ограниченную ценность. Но, учитывая, что я пытаюсь написать сериализаторы без выделения памяти, они были полезны для моих целей.