如果我传递这个序列作为参数,我应该检查序列长度吗?

本文关键字:我应该 检查 参数 如果 | 更新日期: 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,所以我的问题是:

  1. 我应该检查coords的长度,只接受coords.Count == 3吗?
  2. 我应该使用IEnumerable<double>以外的序列类型吗?
  3. 我应该忘记传递一个序列作为参数,为什么?

如果我传递这个序列作为参数,我应该检查序列长度吗?

  1. 是的,您应该检查长度并抛出异常(可能是ArgumentException),如果它是错误的,因为这显然是一个异常情况。

  2. 没有任何类型的长度是类型签名的一部分。但是,您应该使用IList以保证顺序(不像IEnumerable),并且您可以通过索引访问。

  3. 您应该忘记作为IEnumerable传递的原因正是您所描述的。它只是一个不必要的潜在错误来源,而且它使您的签名缺乏描述性,从而降低了代码的可读性。如果可以在编译时防止错误,为什么要放弃它呢?

    然而,你可以考虑创建一个Coordinates类,它只包含Latitude, LongitudeElevation参数。如果你需要做一些事情,比如转换到不同的坐标系统,这也会很有用。

  1. 如果集合中的元素少于3个,则会中断,并且如果有更多元素,则会忽略超过第三个的元素。你至少应该检查一下最小条件。但是,您将如何处理错误,抛出异常吗?这说明了为什么这可能不是一个好主意。

  2. 这是通用集合的正确参数。

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

是否为过多的数据抛出异常由您决定。

希望对你有帮助。