有人可以解释或指出为什么运行时类型检查不发生在示例中-字符串属性可以设置为任何类型值...
在非常意想不到的地方坚持了下来,真的很惊讶
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);
}发布于 2014-06-17 23:40:11
我做了一个小实验:在你的类中添加了一个方法:
static void SetValue1(A a, object v)
{
a.Name = (string)v;
}当然,做SetValue1(a, 123);会抛出InvalidCastException。然后我使用ildasm.exe反汇编了代码。SetValue1看起来像这样:
.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好的,让我们用nop替换强制转换的castclass [mscorlib]System.String,并用ilasm.exe重新编译。
现在,使用错误类型的参数调用SetValue1并产生与动态方法相同的结果。因此,在这种情况下,CLR似乎没有进行类型检查。documentation说:
在即时编译期间,一个可选的验证过程会检查要即时编译为本机代码的方法的元数据和微软中间语言(MSIL),以验证它们是否是类型安全的。如果代码具有绕过验证的权限,则跳过此过程。
在这种情况下,我们在本地机器上运行代码,所以CLR相信IL是有效的。
您可以通过对输出.exe文件运行peverify.exe来手动验证程序集。它将返回一个错误:Program::SetValue1][offset 0x00000004][found ref 'System.Object'][expected ref 'System.String'] Unexpected type on the stack.
有一篇很好的帖子探讨了这个话题:http://www.pcreview.co.uk/forums/net-type-safety-and-net-configuration-tool-t1225543.html
发布于 2013-07-31 22:17:10
我认为这是因为您将参数声明为object(System.Object)。int是System.ValueType:System.Object和A:System.Object,System.Object是所有类(http://msdn.microsoft.com/en-us/library/system.object.aspx)的基类。例如,如果您将typeof(object)更改为typeof(string),您将得到强制转换错误。
编辑:我认为您的示例中禁用了params类型检查,因为您替换了对getter/setter属性的调用。如果您需要对调用动态方法进行类型检查,您可以尝试使用以下代码:
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
pi.PropertyType, // 1, value
}, // parameter types
typeof(OracleUserOlapRepositoryTests), // 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);
//correct
method.Invoke(a, new object[]{a,"test"});
//error
method.Invoke(a, new object[]{a,new List<String>()});
Console.WriteLine(a.Name.GetType().Name);https://stackoverflow.com/questions/17971700
复制相似问题