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

C#如何在运行时设置类私有字段?反射实现方案问询

问题:运行时通过反射设置C#类的私有字段值

我正在学习C#,刚接触反射技术,目前在构建一个WinForms应用的模型类,代码如下(实际包含更多类似_value的字段及其他内容):

public class ParentClass
{
    private int _id;
    private string _value1, _value2, _value3;
    private Random _random;
    private List<string> _registryStuff;
    private User _user;
    private ChildClass1 _childClass1;
    private ChildClass2 _childClass2;


    public ParentClass()
    {
        _user = new User();
        _random = new Random();
        _childClass1 = new ChildClass1();
        _childClass2 = new ChildClass2();
    }

    public User User
    {
        get => _user;
        set => _user = value;
    }

    public int Id
    {
        get => _id; set => _id = _random.Next(1, 100);
    }

    public string Value1
    {
        get => _value1; set => _value1 = _childClass1.Method()[1];
    }

    public string Value2
    {
        get => _value2; set => _value2 = _childClass1.Method()[2];
    }

    public string Value3
    {
        get => _value3; set => _value3 = _childClass1.Method()[3];
    }

    public List<string> RegistryStuff
    {
        get => _registryStuff; set => _registryStuff = GetData();
    }

    private List<string> GetData()
    {
        List<string> keys = new List<string>()
        {
            @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
            @"SOFTWARE\WOW6432Node\Windows\CurrentVersion\Uninstall"
        };

        List<string> result = new List<string>();

        return _childClass2.Method(RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, 
        RegistryView.Registry64), keys, result);
    }
}

// ChildClass1.cs
public class ChildClass1
{
    public string[] Method()
    { 
        //... do stuff...
        // return the string array from there
    }
}

// ChildClass2.cs
public class ChildClass2
{
    public List<string> Method(RegistryKey regKey, List<string> keys, List<string> result)
    { 
        //... do stuff..
        // return the List from there
    }
}

我希望在运行时设置ParentClass中的_id、_value1、_value2、_value3等私有字段的值,请问是否可行?另外,ParentClass.User.Value1、Value2等属性是通过窗体文本框进行设置的。

我原本计划使用反射来实现字段赋值,但只有将属性的setter修改为get => _childClass1.Method()[1]; set => _value1 = value;这类直接赋值字段的形式时,才能通过如下方法正常填充DataGridView:

private static DataTable CreateTable(object obj, DataGridView grid)
{
    DataTable _dTable = new DataTable();
    DataRow _dRow = _dTable.NewRow();

    grid.DataSource = _dTable;
    grid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;

    _dTable.Rows.Add(_dRow);
    _dTable.Columns.Add("PropName", typeof(string));
    _dTable.Columns.Add("PropType", typeof(string));
    _dTable.Columns.Add("PropValue", typeof(string));

    obj.GetType().GetProperties().ToList().ForEach(prop =>
    {
        try
        {
            _dTable.Rows.Add(prop.Name, prop.PropertyType, prop.GetValue(obj));
        }
        catch (Exception e)
        {
            throw;
        }
    });

    return _dTable;
}

请问如何实现运行时设置这些私有字段的值?是否有可行的方案?


解决方案

1. 用反射直接操作私有字段

完全可以通过反射实现私有字段的赋值,核心是使用BindingFlags.NonPublic | BindingFlags.Instance来指定访问私有实例成员。示例代码如下:

// 创建ParentClass实例
var parentInstance = new ParentClass();
var type = parentInstance.GetType();

// 设置_id字段
var idField = type.GetField("_id", BindingFlags.NonPublic | BindingFlags.Instance);
idField?.SetValue(parentInstance, 123); // 直接赋值为123

// 设置_value1字段
var value1Field = type.GetField("_value1", BindingFlags.NonPublic | BindingFlags.Instance);
value1Field?.SetValue(parentInstance, "自定义的Value1值");

// 同理可设置_value2、_value3等字段

2. 关键注意点

  • 破坏封装性:直接修改私有字段绕过了类的公共接口,可能导致类的状态不符合预期逻辑,比如Id属性的setter原本是随机赋值,直接改_id会跳过这个逻辑。
  • 维护风险:如果后续修改字段名称(比如把_value1改成_firstValue),反射代码会直接失效,需要同步更新。
  • 依赖初始化:对于_random、_childClass1这类在构造函数中初始化的字段,直接设置可能引发后续方法调用异常,除非你明确知道这样做的影响。

3. 优化DataGridView填充逻辑

如果需要在DataGridView中展示私有字段,可以在CreateTable方法中添加遍历私有字段的代码:

// 在遍历公共属性之后,添加遍历私有字段的逻辑
type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance).ToList().ForEach(field =>
{
    try
    {
        _dTable.Rows.Add(field.Name, field.FieldType, field.GetValue(obj));
    }
    catch (Exception e)
    {
        // 建议捕获异常并记录,避免程序崩溃
        Debug.WriteLine($"获取字段{field.Name}失败:{e.Message}");
    }
});

内容的提问来源于stack exchange,提问作者jumbotrone

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 18:40:15