C#中手动设置字段值可行,为何反射SetValue设置委托字段失败?
问题原因与解决方案
问题根源
你遇到的错误核心是委托类型不匹配:
- 手动赋值
((Human)ahmet).func = addToConsole时,编译器会自动把addToConsole方法隐式转换为Human类内部定义的addToConsole委托类型。 - 但反射调用
SetValue时,直接传入方法名,CLR会默认把它包装成System.Action<string>类型,而Action<string>和Human.addToConsole是两个完全独立的委托类型,无法直接转换,因此抛出类型转换错误。
解决方法
需要显式将方法转换为Human类内部的addToConsole委托类型,使用Delegate.CreateDelegate方法实现这个转换:
修改反射赋值的代码如下:
// 获取Human类中定义的addToConsole委托类型 Type humanDelegateType = item.GetNestedType("addToConsole"); // 创建对应的委托实例 Delegate humanDelegate = Delegate.CreateDelegate(humanDelegateType, this, "addToConsole"); // 赋值给func字段 item.GetField("func").SetValue(ahmet, humanDelegate);
完整的Form1_Load方法修改后:
private void Form1_Load(object sender, EventArgs e) { Assembly asm = Assembly.GetExecutingAssembly(); foreach (Type item in asm.GetTypes()) { if(item.Name == "Human") { object ahmet = Activator.CreateInstance(item); // ((Human)ahmet).func = addToConsole; // WORKS // 反射赋值的正确写法 Type humanDelegateType = item.GetNestedType("addToConsole"); Delegate humanDelegate = Delegate.CreateDelegate(humanDelegateType, this, nameof(addToConsole)); item.GetField("func").SetValue(ahmet, humanDelegate); item.GetField("name").SetValue(ahmet, "ahmet"); object[] param = { "Ali" }; item.GetMethod("greet").Invoke(ahmet, param); } } }
补充说明
Delegate.CreateDelegate的作用是在运行时将方法绑定到指定的委托类型上,解决了反射场景下无法自动转换委托类型的问题。- 使用
nameof(addToConsole)代替硬编码字符串,能提升代码的可维护性,避免方法名修改后出现错误。
内容的提问来源于stack exchange,提问作者ali demir
相关产品推荐
相关产品推荐

