【问题标题】:.NET: switch vs dictionary for string keys.NET:字符串键的切换与字典
【发布时间】:2010-11-22 23:24:12
【问题描述】:

我有一个业务对象,其中包含大约 15 个不同类型的属性。业务对象还必须实现具有以下方法的接口:

object GetFieldValue(string FieldName);

我可以看到 2 种实现此方法的方法:

使用 switch 语句:

switch ( FieldName )
{
    case "Field1": return this.Field1;
    case "Field2": return this.Field2;
    // etc.
}

使用字典(SortedDictionary 还是 HashTable?):

return this.AllFields[FieldName];

哪个更有效?

补充:忘了说。此方法用于在网格中显示项目。网格将为这些属性中的每一个提供一列。通常会有超过 1000 个项目的网格。这就是我关心性能的原因。

添加 2:

这是一个想法:一种混合方法。制作一个静态字典,其中键是属性名称,值是数组中的索引。字典仅在应用程序启动时填写一次。每个对象实例都有一个数组。因此,查找将是:

return this.ValueArray[StaticDictionary[FieldName]];

字典填充算法可以使用反射。然后将相应地实现属性本身:

public bool Field1
{
    get
    {
        object o = this.ValueArray[StaticDictionary["Field1"]]; 
        return o == null ? false : (bool)o;
    }
    set
    {
        this.ValueArray[StaticDictionary["Field1"]] = value;
    }
}

谁能看出这有什么问题?

还可以更进一步,ValueArray/StaticDictionary 可以放在单独的泛型类型ValueCollection<T> 中,其中T 将指定反射类型。 ValueCollection 也将处理尚未设置值的情况。属性可以简单地写成:

public bool Field1
{
    get
    {
        return (bool)this.Values["Field1"];
    }
    set
    {
        this.Values["Field1"] = value;
    }
}

最后,我又开始怀疑,如果一个简单的 switch 语句可能不会更快更容易维护......

【问题讨论】:

  • 不应该比这两个都慢吗?
  • 性能重要吗(以毫秒为单位)?
  • 对象将显示在一个查询属性的网格中。我通常会在这样的网格中包含大约 1000 个项目。那是 15'000 次反射调用。想想如果他们每个人都花 1 毫秒会发生什么,我不寒而栗。
  • 嗬,好吧,这是相当大的也许反射不是你的情况的好选择

标签: .net dictionary switch-statement


【解决方案1】:
switch:      good efficiency, least maintainable
dictionary:  good efficiency, better maintainability
reflection:  least efficient, best maintainability

提示:忽略效率并只担心可维护性,除非您实际测试过性能并发现这是一个问题。

我并不是说反射是您唯一的选择,只是它允许您根据需要添加/删除和重命名属性,并且不需要保持 switch 语句或字典同步。

【讨论】:

  • 反射将允许在运行时发现您的属性,因此如果您添加/删除或重命名任何,您不需要重新编写任何其他代码(例如 switch 语句或字典初始化)。
  • 我倾向于发现反射的认知开销使它比调度表字典方法更难维护。虽然这可能只是因为我不经常使用反射。 :)
  • 比switch语句更高效的字典?没想到,能详细点吗?
  • @Bubblewrap。它可以用于字符串。对于不那么稀疏的查找,切换会更快。
  • @Rune,我可以向你保证,字典比使用反射更快。存在计算机科学中的哈希表和字典是因为它们可以为数据检索提供比大多数其他数据结构更高的性能。而反射的存在是为了在运行时提供类型的可发现性,而不是出于性能原因。但是不要相信我的话,尝试比较作为实验。
【解决方案2】:

因为你使用的是字符串字典可能会更快。使用字符串时,Switch 本质上会被转换为哈希表。但是如果你使用的是整数或类似的东西,它会被翻译成一个跳转表并且会更快。

请参阅this answer 并提问以了解更多详情

最好的办法是对其进行分析并确定

【讨论】:

    【解决方案3】:

    获取每个属性值的方式对整体性能的影响可能小于渲染网格的方式。

    让我举个例子: 假设您有以下实现:

    private string _latestFieldName = string.Empty;
    private PropertyInfo _propertyInfo;
    
    object GetFieldValue(string FieldName)
    {
      if(FieldName != _latestFieldName)
      {
        _propertyInfo = typeof(yourTypeName).GetProperty(FieldName);
      }
      return _propertyInfo.GetValue(this,null);
    }
    

    如果您的网格渲染使用反射一次渲染一行,则每次都必须获取属性信息。 如果你逐列渲染,你只需要为每个属性获取一次 propertyInfo,因为分支预测几乎每次你只会错过很少的 if 时钟周期时都是正确的。当您已经拥有 PropertyInfo 并且不需要将调用结果转换为 GetValue 时。在速度方面,使用反射非常接近于使用属性的 getter。

    我的意思是在您开始优化使用分析器之前。 (当然如果你不能很好地改变网格你也不能真正优化它)

    【讨论】:

    • 不,我无法更改网格。 :)
    【解决方案4】:

    与字典相比,Switch 实际上有两个好处:

    1. 您可以在默认部分创建自定义异常消息,其中可能包含无效值。如果是字典,您只会得到不包含键名的 KeyNotFoundException。
    2. 您可以处理空值。字典不能将 null 存储为键。

    【讨论】:

      猜你喜欢
      • 2018-09-11
      • 2017-02-11
      • 2015-09-16
      • 2021-12-28
      • 2022-01-15
      • 2020-11-27
      • 1970-01-01
      • 2015-12-25
      • 2017-09-13
      相关资源
      最近更新 更多