我一直在分析我的代码,发现System.Array.IndexOf
正在分配相当多的内存。我一直在试图找出为什么会发生这种情况。
public struct LRItem
{
public ProductionRule Rule { get; } // ProductionRule is a class
public int Position { get; }
}
// ...
public List<LRItem> Items { get; } = new List<LRItem>();
// ...
public bool Add(LRItem item)
{
if (Items.Contains(item)) return false;
Items.Add(item);
return true;
}
我假设 IndexOf
是由 Items.Contains
调用的,因为我认为 Items.Add
没有任何业务检查索引。我尝试查看 reference source和 .NET Core source但无济于事。这是 VS 分析器中的错误吗?这个函数实际上是在分配内存吗?我可以以某种方式优化我的代码吗?
最佳答案
我知道这可能有点晚了,但如果其他人有同样的问题......
何时 List<T>.Contains(...)
被调用,它使用 EqualityComparer<T>.Default
比较各个项目以查找您传入的内容[1]。 docs说一下EqualityComparer<T>.Default
:
The Default property checks whether type T implements the System.IEquatable interface and, if so, returns an EqualityComparer that uses that implementation. Otherwise, it returns an EqualityComparer that uses the overrides of Object.Equals and Object.GetHashCode provided by T.
自从您的 LRItem
没有实现 IEquatable<T>
,然后又使用 Object.Equals(object, object)
。因为LRItem
是一个结构体,那么它最终会被装箱为 object
所以它可以传入 Object.Equals(...)
,这是分配的来源。
解决这个问题的简单方法是从文档中获取提示并实现 IEquatable<T>
接口(interface):
public struct LRItem : IEquatable<LRItem>
{
// ...
public bool Equals(LRItem other)
{
// Implement this
return true;
}
}
这现在将导致 EqualityComparer<T>.Default
返回一个专门的比较器,不需要装箱 LRItem
结构,从而避免分配。
[1] 我不确定自从提出这个问题以来是否发生了变化(或者可能是 .net 框架与核心差异或其他什么),但是 List<T>.Contains()
不打电话Array.IndexOf()
如今。无论哪种方式,它们都确实遵循 EqualityComparer<T>.Default
,这意味着这在任何一种情况下都应该仍然相关。
关于c# - System.Array.IndexOf 分配内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52233941/