C#局部数组IReadOnlyCollection / IReadOnlyList优化远程对象创建

时间:2016-10-29 23:35:43

标签: 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;
        }
    }

1 个答案:

答案 0 :(得分:2)

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

数组声明的简写语法

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

与(显示&#39;推断语法&#39;)

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

基本规则是:new 始终创建新对象/实例。要仅创建一次(数组)对象,只需创建一次。然后可以使用成员/字段共享单个阵列实例。这个&#39;吊装&#39;必须手动完成。

// 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);
}

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

Rgb3案例完全避免了数组创建,它避免了一些方法调用,并且避免了进行广义集合的开销包含&#39;循环&#39;逻辑。这将是最快的 - 如果/这样的事情 - 只是因为它做得最少。

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

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

 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(..)或类似。