【问题标题】:C# Right way to update Data using getter and setter in Generic Data (Data : INotifyPropertyChanged)C# 在通用数据中使用 getter 和 setter 更新数据的正确方法(数据:INotifyPropertyChanged)
【发布时间】:2020-06-03 11:59:12
【问题描述】:

我对 C# 很陌生,想知道处理通用数据的正确方法(不浪费任何资源)。

我有一个 BindingList 用于绑定 dataGridView.DataSource。

下面是更新数据值的示例代码:问题是将“计算代码”放在getter还是setter中更有效。

如果有一种被认为是“最佳实践”的方法,请也告诉我。

public class Data : INotifyPropertyChanged
{
    private float number;
    public string Code
    {
        get => Number; //  get => Number / 100     which one is more efficient?
        set { Number = value / 100; OnPropertyChanged(); }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] string name = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

... Data 类的使用方式如下:

public partial class Form1 : Form
{
    private BindingList<Data> dataList = new BindingList<Data> { new Data { Code = "1"  } };

    protected override void OnHandleCreated(EventArgs e)
    {
        // When main form is ready to handle messages the binding happens.
        base.OnHandleCreated(e);
        myDataGridView.DataSource = dataList;
        myDataGridView.Columns["Code"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
    }
    public Form1()
    {
        InitializeComponent();
    }
}

【问题讨论】:

  • 您的代码示例很有趣,因为它指出基础字段类型(在本例中为 float)并不总是与设置它的属性类型相同(在本例中string) 并且我们确实有时必须在 {get;设置;}

标签: c# datagridview getter-setter bindinglist


【解决方案1】:

问:“问题是是否将“计算代码”放入getter。”

A:简短回答:在 set 中计算一次,而不是在每个 get 中计算一次。

长答案:

我注意到您的“代码”属性是一个字符串,但基础值似乎是一个浮点数。没关系,但我有一些优化建议:

  1. 显然,'Code' 属性设置器中的输入字符串 value 必须在某些时候进行解析才能执行代码中显示的浮点计算。 float.Parse() 方法将抛出一个硬异常,如此处所述。确保向输入字符串添加一些验证代码,如果无法解析,则正常失败。
  2. 要触发 PropertyChanged 事件,我建议使用以下形式:使用 nameof 关键字并使 OnPropertyChanged 受保护虚拟,以便继承的类也可以触发该事件。

  3. 这当然只是一种意见,但我会在 setter 中进行一次计算,而不是在 getter 中。但如果它存储为浮点数,我会在 getter 中执行 ToString()。

  4. 我没有看到 setter 中的短期计算有什么害处。如果执行计算是某种长时间运行的任务,请考虑改用方法,并可能将其作为任务异步执行。


    public string Code
    {
        get => _number.ToString(); // 'Some' inefficiency here, but probably storing as float is preferred.
        set 
        {
            // I would offer that doing this ONCE in the setter
            // is more efficient than calculating on every get.
            float floatValue = float.Parse(value);  // Warning: Will throw exception 
                                                    // is value if unparsable input string
            _number = floatValue / 100;

            // Preferred form here is to use the 'nameof' keyword
            OnPropertyChanged(new PropertyChangedEventArgs(nameof(Code)));
        }
    }
    // I suggest some other notation than 'Number' because this
    // is a private field and when you say 'Number' the expectation is 
    // a public property. I see this notation often in Google source code
    // to indicate a 'private field' and have adopted it myself:
    private float _number;

    public event PropertyChangedEventHandler PropertyChanged;

    // This is customarily 'protected virtual'
    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        PropertyChanged?.Invoke(this, e);
    }

由于其中很多都与“风格点”有关,因此还有其他观点,而不是我自己的观点。我确实相信有足够的内容来证明发布此答案的合理性,并希望它为您提出的问题提供一些见解。

【讨论】:

  • 很高兴我能提供帮助!
  • 如果您正在深入研究 DataGridView,我还写了一些关于该主题的其他答案,包括针对初学者的 this oneIVSoftware @ GitHub 上还有十几个 Winforms 示例链接回 StackOverflow 问题。您(和每个人)肯定会被邀请四处看看,看看是否有任何您认为值得的东西。
  • @hyukkyulee 我想说的不是“错误”——我会使用“快乐事故”这个词,因为这种情况并非闻所未闻。
  • @IVSoftware 我在虚拟模式下使用 DataGridView 时遇到了问题。在更新我的数据(例如:添加/插入一行)时,DataGridView 在更新过程中轮询 CellValueNeeded,而不是更新后台源(因为两者实际上不能并行发生)。我发布了question,但没有得到任何反馈。一般来说,我发现 DataGridView 控件在虚拟模式下使用时非常有问题。
  • 有证据表明,如果线程和消息队列得到很好的理解,DGV VirtualMode 不会出现错误并且可以提供良好的性能。你知道我在汽车 IC 验证测试工作。 1 ppm error way too high 和检测此类错误需要更高的精度。 (抱歉重复一遍,我知道那在我的 SO 个人资料中......)。 DGV 是我们通往一堆 SQLite 数据库的窗口,这些数据库拥有数百万个数据点以进行交叉关联。它奏效了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-10
相关资源
最近更新 更多