一般来说,托管代码不应该导致访问冲突. 这在本地代码或unsafe
代码中发生. 但不知何故,我对一些Reflection. Emit代码进行了一些摆弄,因为它看起来应该太简单了,不会出错,我得到了访问违规.
using System.Collections;
using System.Reflection;
using System.Reflection.Emit;
namespace Repro
{
internal class Program
{
static void Main()
{
TypeBuilder typeBuilder = BuildType();
var realType = typeBuilder.CreateType();
var arr = Array.CreateInstance(realType, 10);
var caster = typeof(Enumerable).GetMethod("Cast")!.MakeGenericMethod(realType);
var typedArr = caster.Invoke(null, [arr]);
var sorter = realType.GetMethod("Sort")!;
var sorted = sorter.Invoke(null, [typedArr])!;
var bomb = ((IEnumerable)sorted).Cast<object>().ToArray(); //blows up here
}
private static TypeBuilder BuildType()
{
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new("MyAssembly"), AssemblyBuilderAccess.RunAndCollect);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MyAssembly");
var typeBuilder = moduleBuilder.DefineType("MyType", TypeAttributes.Public, typeof(ValueType));
var field = typeBuilder.DefineField("field", typeof(int), FieldAttributes.Public);
var extractor = typeBuilder.DefineMethod("GetField", MethodAttributes.Private | MethodAttributes.Static, typeof(int), [typeof(int)]);
var il = extractor.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, field);
il.Emit(OpCodes.Ret);
var enumType = typeof(IEnumerable<>).MakeGenericType(typeBuilder);
var impl = typeBuilder.DefineMethod("Sort", MethodAttributes.Public | MethodAttributes.Static, enumType, [enumType]);
il = impl.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldtoken, extractor);
var getMethod = typeof(MethodBase).GetMethod("GetMethodFromHandle", [typeof(RuntimeMethodHandle)])!;
il.Emit(OpCodes.Call, getMethod);
var orderFunc = typeof(Enumerable).GetMethods().Single(m => m.Name == "OrderBy" && m.GetParameters().Length == 2);
il.Emit(OpCodes.Call, orderFunc.MakeGenericMethod(typeBuilder, typeof(int))); // call Enumerable.OrderBy(enumerable, extractor)
il.Emit(OpCodes.Ret);
return typeBuilder;
}
}
}
剥离所有的反射,这应该生成大致等同于以下代码:
using System.Linq;
struct MyType
{
public int field;
private static int GetField(MyType value) => value.field;
public static IEnumerable<MyType> Sort(IEnumerable<MyType> values)
{
return values.OrderBy(MyType.GetField);
}
}
//in Main
var arr = new MyType[10];
var sorted = MyType.Sort(arr);
var bomb = sorted.ToArray();
但不知何故,在bomb
线上,它抛出了AccessViolationException
. 我很想知道为什么,以及我如何解决它.