List <t> .RemoveAll()效率/编译器优化

时间:2019-04-05 08:31:53

标签: c# arrays list linq compiler-optimization

关于效率,有谁知道编译器是否足够聪明,以使 在以下代码的每次循环中创建包含1, 3, 5的数组?

var foo = new List<int> { 1, 2, 3, 4, 5 };
foo.RemoveAll(i => new[] { 1, 3, 5 }.Contains(i));

出于可读性考虑,我更喜欢它,但不是出于性能考虑。

3 个答案:

答案 0 :(得分:13)

答案是肯定的,它不会优化数组的分配

基本上,每次调用谓词时,它都会检查编译器生成的类,并初始化一个新数组以调用Contains(如您所见,here

private sealed class <>c
{
    public static readonly <>c <>9 = new <>c();

    public static Predicate<int> <>9__0_0;

    internal bool <M>b__0_0(int i)
    {
        // bam!
        int[] obj = new int[3];
        RuntimeHelpers.InitializeArray(obj, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
        return Enumerable.Contains(obj, i);
    }
}

答案 1 :(得分:4)

如@Michael Randall所写,看来不可能。

我同意,您所质疑的代码具有很好的可读性,该列表位于RemoveAll方法中。但是,只有一次实例,我有三种想法:

int[] a = null;
foo.RemoveAll(i => (a ?? (a = new[] { 1, 3, 5 })).Contains(i));

这实际上是您的,几乎不需要任何外部变量。

 foo = foo.Except(new[] { 1, 3, 5 }).ToList();

这实际上是使用Linq的不错的解决方案。

 new List<int>{1, 3, 5}.ForEach(x => foo.Remove(x));


 new[] {1, 3, 5}.Iterate(x => foo.Remove(x));

这是我要做的。在几乎所有代码中,我都有我的扩展方法“迭代”,以避免需要foreach。而且,我也不想一直“ toList”所有内容以创建一个.ForEach(..)

static class Extensions
{
    public static void Iterate<TSource>(this IEnumerable<TSource> source, Action<TSource> action)
    {
        foreach (var item in source)
        {
            action.Invoke(item);
        }
    }
}

答案 2 :(得分:0)

由于编译器不是那么聪明,所以我们必须比他聪明。

var foo = new List<int> { 1, 2, 3, 4, 5 };
var bar = new HashSet<int>() { 1, 3, 5 };
foo.RemoveAll(i => bar.Contains(i));