C# 本地数组 IReadOnlyCollection/IReadOnlyList 优化对象创建

标签 c# readonly

以下三种方法是否具有等效的垃圾回收行为? #1 有点牵强,但今天的 C# 编译器是否足够聪明,可以在每次调用方法时优化#2 中的对象创建?我特别不想在方法之外提升数组初始化。

    public Boolean IsRgb1(string color)
    {
        string[] colors = { "red", "green", "blue" };
        return colors.Contains(color);
    }

    public Boolean IsRgb2(string color)
    {
        IReadOnlyCollection<string> colors = new[] { "red", "green", "blue" };
        return colors.Contains(color);
    }

    public Boolean IsRgb3(string color)
    {
        switch(color)
        {
            case "red":
            case "green":
            case "blue":
                return true;
            default:
                return false;
        }
    }

最佳答案

没有与这些类型相关的编译器魔术。每次调用时,总是在 Rgb1 和 Rgb2 中创建一个数组。

数组声明简写语法

string[] colors = { "red", "green", "blue" };

与(显示“推导语法”)相同

string[] colors = new string[3] { "red", "green", "blue" };

基本规则是:new 总是 创建一个新的对象/实例。要只创建一次(数组)对象,只创建一次。然后可以使用成员/字段共享单个数组实例。这种“提升”必须手动完成。

// One array created and stored for later use ..
private static string[] Colors = { "red", "green", "blue" };
// .. independent of number of times this method is called
public Boolean IsRgb(string color)
{
    return Colors.Contains(color);
}

在这两种情况下,包含来自 IEnumerable<T>作为T[]IReadOnlyList<T>是 IEnumerable1 的子类型并且符合 LINQ Contains 扩展方法。将使用相同的 IEnumerable Contains 实现(LINQ To Objects),并且应用于数组的任何特化都应适用于这两种情况。

Rgb3 案例完全避免了数组创建,它避免了一些方法调用,并且避免了执行包含“循环”逻辑的广义集合的开销。它将是最快的 - 如果/在这种情况下 - 仅仅是因为它要做的事情最少。

一个简单的字符串 switch 语句可以被认为是编写一系列 if..else if.. 的替代方法。比较相同的值。在这种情况下,没有每次方法调用都会创建新对象:字符串文字已被保留,显然没有新数组。

或者,考虑简单地使用单个表达式:

 return color == "red" || color == "green" || color == "blue";

1由于类型继承比较困惑,这里摘录一小段:

T[] -> IEnumerable<T> (Contains as Extension Method)
    -> IList<T> -> ICollection<T> (Contains in Interface) -> IEnumerable<T>
    -> IReadOnlyList<T> -> IEnumerable<T>
                        -> IReadOnlyCollection<T> -> IEnumerable<T>

T[]IReadOnlyList<T> 的子类型Rgb2 中的赋值导致隐式向上转换——变量仍然命名新创建的数组对象。 IEnumerable<T>.Contains的选择发生在编译时,因此 Rgb1 和 Rgb2 方法都将使用扩展方法 IEnumerable<T>.Contains在原始创建的数组对象上。使用 ICollection<T>.Contains需要 ((IList<string>)colors).Contains(..)或类似的。

关于C# 本地数组 IReadOnlyCollection/IReadOnlyList 优化对象创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40324716/

相关文章:

c# - 以编程方式分离 SQL Server 数据库以复制 mdf 文件

c# - WPF 中的 UI 自动化

c# - 文件更改时通知?

C++ - 使用模板公开返回 const 引用并私下返回非 const 引用

qt - "file.open(QIODevice::ReadOnly)"是什么意思?

c# - ApiController 中的 Url.Route 不包含主机名

c# - 如何在代码中动态地将新的视觉状态添加到自定义控件模板?

ios - 为只读对象的属性赋值

sql-server - 如何使用 T-SQL 检测 SQL Server 数据库的只读状态?