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

时间:2014-06-16 23:30:29

标签: c# constructor initialization

我正在实现一个名为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. 我是否应该忘记将序列作为参数完全传递,为什么?

4 个答案:

答案 0 :(得分:2)

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

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

  3. 是的,正如您所指出的,参数的数量对您的对象非常重要。允许集合删除该约束,并将错误放入运行时而不是编译时。我可以看到允许集合构造函数的任何优点。

答案 1 :(得分:2)

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

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

  3. 您应该忘记以IEnumerable传递,原因正如您所描述的那样。它只是一个不需要的潜在错误来源,而且它使您的签名不那么具有描述性,因此会降低您的代码的可读性。如果你可以在编译时防止错误,为什么要传递它?

    但是,您可以考虑创建一个仅包含CoordinatesLatitudeLongitude参数的Elevation类。如果你需要做一些事情,比如转换到不同的坐标系,这也可以提供用。

答案 2 :(得分:2)

我实际上也不会通过IEnumerable(同意其他人)。如果您可以使用序列来表示位置,那么为什么需要首先创建位置结构?您可以在代码中的所有位置使用IEnumerable,不是吗? : - )

软件的一个重要原则是实现所需要的。你的代码中是否有IEnumerble代表位置?如果没有,则跳过此构造函数,并仅在需要时添加它。但是,如果您有这样的需要,那么添加一个对参数计数不完全为3的检查以避免编码错误,如果坐标或高程的顺序与您预期的顺序不同,则可能仍然会出现编码错误。

在你的情况下,Position似乎是应该通过构造函数实例化的结构,例如

Position p = new Position(1, 2, 3);

或通过初始化属性,例如

Position p = new Position
{
    Latitude = 1,
    Longitude = 2,
    Elevation = 3
};

答案 3 :(得分:1)

我同意这里的其他受访者 - 这个构造函数似乎可能导致问题,因为它没有清楚地记录所需的双值的数量。

但是,如果您需要来执行此操作,例如因为您有复杂的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();
    }
}

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

希望有所帮助。