Can someone explain or point to explanation why runtime types check not occurs in sample below - string property can be set to any type value ...
Stuck with this in very unexpected place and was really surprised
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace Dynamics
{
internal class Program
{
private static void Main(string[] args)
{
var a = new A();
a.Name = "Name";
Console.WriteLine(a.Name.GetType().Name);
PropertyInfo pi = a.GetType().GetProperty("Name");
DynamicMethod method = new DynamicMethod(
"DynamicSetValue", // NAME
null, // return type
new Type[]
{
typeof(object), // 0, objSource
typeof(object), // 1, value
}, // parameter types
typeof(Program), // owner
true); // skip visibility
ILGenerator gen = method.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, pi.GetSetMethod(true));
gen.Emit(OpCodes.Ret);
SetValue setMethod = (SetValue)method.CreateDelegate(typeof(SetValue));
int val = 123;
setMethod(a, val);
Console.WriteLine(a.Name.GetType().Name);
A anotherA = new A();
anotherA.Name = "Another A";
setMethod(a, anotherA);
Console.WriteLine(a.Name.GetType().Name);
}
}
public class A
{
public string Name { get; set; }
}
public delegate void SetValue(object obj, object val);
}
I did a little experiment: Added a method to your class:
static void SetValue1(A a, object v)
{
a.Name = (string)v;
}
Doing SetValue1(a, 123);
throws InvalidCastException
of course.
I then disassembled the code using ildasm.exe
. SetValue1
looks like this:
.method private hidebysig static void SetValue1(class ConsoleApplication2.A a,
object v) cil managed
{
// Code size 15 (0xf)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: castclass [mscorlib]System.String // <--- replace this with nop
IL_0008: callvirt instance void ConsoleApplication2.A::set_Name(string)
IL_000d: nop
IL_000e: ret
} // end of method Program::SetValue1
Ok, let's replace the cast castclass [mscorlib]System.String
with nop
and recompile with ilasm.exe
.
Now the call to SetValue1 with wrong type argument passes and produces the same result as your dynamic method. So it would seem that CLR is not doing type checking in this case. The documentation says:
During just-in-time (JIT) compilation, an optional verification process examines the metadata and Microsoft intermediate language (MSIL) of a method to be JIT-compiled into native machine code to verify that they are type safe. This process is skipped if the code has permission to bypass verification.
In this case, we are running code on local machine, so the CLR trusts that the IL is valid.
You can manually verify the assembyl by running peverify.exe
on the output .exe file. It will return with an error: Program::SetValue1][offset 0x00000004][found ref 'System.Object'][expected ref 'System.String'] Unexpected type on the stack.
There is a very good post that explores this topic: http://www.pcreview.co.uk/forums/net-type-safety-and-net-configuration-tool-t1225543.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With