.net Framework 4.7.2...
Compiled expressions can access private fields. When I use exactly the same expression and write it to a dynamic assembly, using CompileToMethod
, I get a System.FieldAccessException
while trying to read the private field.
Is there anything I can do to allow the dynamic assembly to have the same access privileges that a compiled expression does? There is ancient lore that says you cannot. But I can't find anything resembling a primary source for that claim. I can't believe there is not some form of assembly attributes or permissioning that would allow access.
Can I do it if I save the assembly instead? (Writing cached marshalling assemblies to disk is a likely feature in the future).
The application is marshalling of structs to streams in a domain-specific computer music language. Serialization is not an option (another example of dynamic code in dynamic assemblies that violates access).
Example code:
The lambda expression successfully reads the value of the private field of ComplexStruct (given below). If the same expression is emitted to a dynamic assembly using CompileToMethod, it fails with an access exception.
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);
A struct with private fields:
// (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;
}
}
Creation of the assembly:
AppDomain myAppDomain = Thread.GetDomain();
AssemblyName myAsmName = new AssemblyName();
myAsmName.Name = "DynamicAssembly";
this.saveAssembly = ServiceBase.DEBUG;
assemblyBuilder = myAppDomain.DefineDynamicAssembly(
myAsmName,
saveAssembly? AssemblyBuilderAccess.RunAndSave: AssemblyBuilderAccess.RunAndCollect);
DynamicMethod
s to skip visibility checks. Have a look at the constructor list, there are a few constructors that have askipVisibility
boolean parameter. Ages ago i tried to find out how and why that works, but i got lost in process. Also have a look at theownerType
ormodule
parameters there: learn.microsoft.com/en-us/dotnet/api/… – Taken