如果我传递这个序列作为参数,我应该检查序列长度吗?
本文关键字:我应该 检查 参数 如果 | 更新日期: 2023-09-27 18:08:49
我正在实现一个名为Position
的结构体,它代表一个包含属性double Latitude, Longitude, Elevation
的地理位置。
它的构造函数之一是
public Position(double lat, double lon, double elev)
,我创建了一个像这样的:
public Position(IEnumerable<double> coords) : this(
coords.ElementAt(0),
coords.ElementAt(1),
coords.ElementAt(2)
) {}
这是工作,但有些似乎是"错误的",我可以通过任何长度超过3的IEnumerable
,所以我的问题是:
- 我应该检查
coords
的长度,只接受coords.Count == 3
吗? - 我应该使用
IEnumerable<double>
以外的序列类型吗? - 我应该忘记传递一个序列作为参数,为什么?
-
是的,您应该检查长度并抛出异常(可能是
ArgumentException
),如果它是错误的,因为这显然是一个异常情况。 -
没有任何类型的长度是类型签名的一部分。但是,您应该使用
IList
以保证顺序(不像IEnumerable
),并且您可以通过索引访问。 -
您应该忘记作为
IEnumerable
传递的原因正是您所描述的。它只是一个不必要的潜在错误来源,而且它使您的签名缺乏描述性,从而降低了代码的可读性。如果可以在编译时防止错误,为什么要放弃它呢?然而,你可以考虑创建一个
Coordinates
类,它只包含Latitude
,Longitude
和Elevation
参数。如果你需要做一些事情,比如转换到不同的坐标系统,这也会很有用。
-
如果集合中的元素少于3个,则会中断,并且如果有更多元素,则会忽略超过第三个的元素。你至少应该检查一下最小条件。但是,您将如何处理错误,抛出异常吗?这说明了为什么这可能不是一个好主意。
-
这是通用集合的正确参数。
-
是的,正如您所指出的,参数的数量对您的对象非常重要。允许集合消除了该约束,并将错误置于运行时而不是编译时。
我实际上也不会通过IEnumerable
(同意其他人的意见)。如果您可以使用序列来表示Position,那么为什么首先需要创建Position结构体呢?你可以在代码的所有地方使用IEnumerable
,不是吗?: -)
软件的一个重要原则是实现需要的东西。你是否在代码的其他地方有IEnumerble
来表示位置?如果没有,则跳过此构造函数,只在需要时添加它。但是,如果您有这样的需要,那么请添加一个检查参数计数是否不完全为3,以避免编码错误,如果坐标或标高的顺序与您期望的顺序不同,仍然可能发生编码错误。
在你的例子中,Position似乎是应该被实例化的结构,或者通过构造函数,例如
Position p = new Position(1, 2, 3);
或通过初始化属性,例如
Position p = new Position
{
Latitude = 1,
Longitude = 2,
Elevation = 3
};
我同意其他回复者的观点——这个构造函数似乎可能会导致问题,因为它没有清楚地记录所需的双值的数量。
但是,如果您需要这样做,例如,因为您有返回地理位置信息的复杂Linq查询,您希望从中构造位置,那么我注意到您的构造函数实际上遍历Enumerable三次,每次调用ElementAt()一次。这可能会在使用复杂枚举数的情况下导致性能问题。下面稍微不透明的代码避免了这个问题,并且在给定的数据不足时抛出ArgumentException:public class Position
{
public double lat, lon, elev;
public Position(IEnumerable<double> coords)
{
if (coords == null)
{
throw new ArgumentException();
}
using (var enumerator = coords.GetEnumerator())
{
if (enumerator != null && enumerator.MoveNext())
{
this.lat = enumerator.Current;
if (enumerator.MoveNext())
{
this.lon = enumerator.Current;
if (enumerator.MoveNext())
{
this.elev = enumerator.Current;
/*
if (enumerator.MoveNext())
{
// What to do here?? throw an exception?
throw new ArgumentException();
}*/
return;
}
}
}
}
throw new ArgumentException();
}
}
是否为过多的数据抛出异常由您决定。
希望对你有帮助。