Следующий код выдает исключение, которое говорит о том, что оно может дестабилизировать среду выполнения.
var method = new DynamicMethod("CallObjectToString", typeof(string),new[]{ typeof(object)});
var ilgen =method.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, typeof(object).GetMethod("ToString"));
ilgen.Emit(OpCodes.Ret);
var @delegate = method.CreateDelegate(typeof(Func<object, string>)) as Func<object,string>;
@delegate(new object());
Изменение Opcodes.Call
на Opcodes.CallVirt решает проблему.Это все хорошо, но я могу использовать typebuilder для создания динамического типа, который имеет статический метод, построенный с использованием (MethodBuilder), который имеет точно того же IL, затем использовать CreateDelegate, и он не вызовет это исключение,Фактически, используя methodbuilder, вы можете заставить что-то вызывать виртуальные методы совершенно другого объекта, даже не того, от которого этот тип наследует.
Еще более удивительно, что если я сделаю что-то вроде new object().ToString()
, это такжевыдает инструкцию call
в IL, а не callvirt
.
Если незаконно вызывать виртуальный метод, используя call
, за исключением случая вызова базового метода в переопределении экземпляра,тогда почему CLR позволяет делать такой метод статически для другого типа?Или разрешить отправку call
инструкций для известных ненулевых объектов?
Или это проблема только для кода, сгенерированного с помощью DynamicMethod
?
Редактировать: я не спрашиваю ус точки зрения производительности, мне действительно все равно.Приведенный ниже код, хотя и немного более сложный, создает делегата, который выполняет дестабилизирующее действие без дестабилизации среды выполнения.Это весь вопрос.Почему один законный, а другой незаконный?
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("SomeAssembly"), AssemblyBuilderAccess.Run) ;
var moduleBuilder = assemblyBuilder.DefineDynamicModule("SomeModule");
var typeBuilder = moduleBuilder.DefineType("SomeType");
var methodBuilder = typeBuilder.DefineMethod("SomeStaticMethod",MethodAttributes.Public | MethodAttributes.Static,typeof(string),new[]{typeof(object)});
var ilgen = methodBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, typeof(object).GetMethod("ToString"));
ilgen.Emit(OpCodes.Ret);
var newType = typeBuilder.CreateType();
var @delegate = Delegate.CreateDelegate(typeof(Func<object, string>),newType.GetMethod("SomeStaticMethod")) as Func<object,string>;
@delegate(new object());