You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 10:50:21