CA1819:属性不应该返回数组——正确的替代方法是什么?
本文关键字:方法 是什么 属性 不应该 返回 数组 CA1819 | 更新日期: 2023-09-27 18:11:46
我以前遇到过这个FxCop规则,对于如何解决违规(thread1, thread2)并不满意。我现在有另一个需要纠正违反CA1819类型的情况。
具体来说,我有一个算法库,它在曲线(x,y)上执行一些解析计算,有一个像这样的公共"输入对象":
public class InputObject
{
public double[] X { get; set; }
public double[] Y { get; set; }
// + lots of other things well
}
对象的X和Y属性在库中的数百个位置使用,通常使用索引。输入对象永远不会被算法改变,但实际上即使这样也不重要。同样,.Length
也经常被调用。这是一个数学库,double[]
是其中的标准数据类型。在任何情况下,修复CA1819将需要相当多的工作。
我考虑使用List<double>
,因为列表支持索引,并且与数组非常相似,但我不确定这是否会减慢算法,或者FxCop是否会对这些列表感到满意。
替换这些double[]
属性的最佳选择是什么?
如果它对外部消费者是只读的,并且消费者不想通过索引访问它,那么最好是有一个IEnumerable<>
类型的公共只读属性,并带有可以添加和删除的方法访问器,这样你就不必把你的数组暴露给别人来弄乱。
如果你需要访问索引器,那么将它公开为IList<>
类型的只读属性,并可能返回一个只读实例,并带有添加和删除的方法。
这种方式可以保持内部列表的封装,并允许消费者以只读方式访问它
有时候FxCop在我看来是夸大其词了。
这完全取决于你要做什么,如果你正在编写一个需要安全性和非常干净的代码的复杂系统,你应该返回该数组的只读版本。也就是说,将数组转换为IEnumerable,就像devdigital建议的那样,或者使用Mohamed Abed的ImmutableArray这个好主意,我更喜欢。
如果你正在编写需要高性能的软件…在c#中,没有什么比数组更能提高性能了。对于迭代和读取,数组的性能要高得多。
如果性能真的很重要,我建议你忽略这个警告。如果不是太干净的话,返回一个只读数组仍然是合法的。
for (int i = 0; i < array.Length; ++i) { k = array[i] + 1; }
对于c#中的大数组来说,这是非常快的:它避免了数组边界检查。它的性能与C编译后的代码非常相似。
我一直希望在c#中有一个"只读数组"类型:)但是没有希望看到它。
如你的链接所示:
要修复违反此规则的情况,要么使属性成为方法,要么更改属性以返回一个集合。
使用像List
这样的集合应该不会对性能产生重大影响。
这里最大的问题并不是你的库对这些值做了什么(这是一个潜在的问题,尽管是一个更容易管理的问题),而是调用者可能对这些值做什么。如果您需要将它们视为不可变的,那么您需要确保库使用者不能在其原始赋值之后更改内容。这里的简单修复方法是创建一个接口,公开库使用的所有数组成员,然后为实现该接口的数组创建一个不可变的包装器类,以便在InputObject
类中使用。。:
public interface IArray<T>
{
int Length { get; }
T this[int index] { get; }
}
internal sealed class ImmutableArray<T> : IArray<T>
where T : struct
{
private readonly T[] _wrappedArray;
internal ImmutableArray(IEnumerable<T> data)
{
this._wrappedArray = data.ToArray();
}
public int Length
{
get { return this._wrappedArray.Length; }
}
public T this[int index]
{
get { return this._wrappedArray[index]; }
}
}
public class InputObject
{
private readonly IArray<double> _x;
private readonly IArray<double> _y;
public InputObject(double[] x, double[] y)
{
this._x = new ImmutableArray<double>(x);
this._y = new ImmutableArray<double>(y);
}
public IArray<double> X
{
get { return this._x; }
}
public IArray<double> Y
{
get { return this._y; }
}
//...
}
如果T是可变的,那么"不可变"数组内容中的元素仍然是可变的,但至少对于double类型是安全的。
将array[]改为IEnumerable:
public class InputObject
{
public IEnumerable<double> X { get; set; }
public IEnumerable<double> Y { get; set; }
// + lots of other things well
}