C#中的新类型定义

我正在寻找定义新类型并在C#中使用它的可能性,如下所示:

class级定义:

public class Position { public double180 Longitude { get; set; } // double180 is a type within a range -180 and 180 public double90 Latitude { get; set; } // double90 is a type within a range of -90 and 90 } 

用法:

 var position = new Position { Longitude = 45, Latitude = 96 // This line should give an error while initializing the object }; 

一种类型可能有点过分,但如果你想要一种,这是一个好的开始:

 struct Double180 : IEquatable { private readonly double value; public Double180(double d) { if (d < -180 || d > 180) { throw new ArgumentOutOfRangeException("d"); } this.value = d; } public static implicit operator double(Double180 d) { return d.value; } public static explicit operator Double180(double d) { return new Double180(d); } public override string ToString() { return this.value.ToString(); } public bool Equals(Double180 other) { return this.value == other.value; } public override bool Equals(object obj) { return obj is Double180 && this.Equals((Double180)obj); } public override int GetHashCode() { return this.value.GetHashCode(); } public static bool operator ==(Double180 a, Double180 b) { return a.Equals(b); } public static bool operator !=(Double180 a, Double180 b) { return !a.Equals(b); } } 

当然,还有更多的接口要实现,例如IConvertibleIComparable会很好。

正如您所看到的,您知道它从哪里开始,但您不知道它的结束位置。

如其他答案所示,settervalidation器可能是更好的主意。

您不一定需要新类型。 您可以手动编写用于validation值的setter,而不是使用auto属性:

 public double Latitude { get { return mLatitude; } set { if (value > 90 || value < -90) { throw new ArgumentOutOfRangeException("Invalid latitude"); } mLatitude = value; } } private double mLatitude; 

如果要重用此代码,可以定义自己的类型并在其中使用上面的setter; 然后提供适当的构造函数和转换运算符。

您最好添加System.ComponentModel.DataAnnotations并使用[Range],如下所示:

 public class Position { [Range(-180, 180)] public double Longitude { get; set; } [Range(-90, 90)] public double Latitude { get; set; } } 

使用double并让setter检查值:

 private double _longitude; public double Longitude { get { return _longitude; } set { if(value < -180 || value > 180) { throw new ArgumentException("value"); } _longitude = value; } } 

向setter添加validation步骤:

 private double m_Latitude; public double Latitude { get{return m_Latitude;} set { if(value < -90 || value > 90) throw new ArgumentException("value"); m_Latitude = value; } } 

请注意,在提供属性实现时,您需要添加成员变量来存储基础属性值。

我基本上有了这个想法:validationsetter中的输入。 在类型定义方面,似乎Structs是最好的。 最后,我将在我的项目中使用以下内容。

 public struct Coordinate { private readonly double _x; private readonly double _y; ///  /// Longitude ///  public double X { get { return _x; } } ///  /// Latitude ///  public double Y { get { return _y; } } ///  /// Initiates a new coordinate. ///  /// Longitude [-180, 180] /// Latitude [-90, 90] public Coordinate(double x, double y) { if (x < -180 || x > 180) throw new ArgumentOutOfRangeException( "x", "Longitude value must be in range of -180 and 180."); if (y < -90 || y > 90) throw new ArgumentOutOfRangeException( "y", "Latitude value must be in range of -90 and 90."); _x = x; _y = y; } } 

然后我会这样使用

 var position = new Coordinate(46.32, 34.23); 

谢谢大家的宝贵意见。

我喜欢文档作为系统的一部分:

 public class Position { ///  /// ... /// /// A value within a range -180 and 180 ///  public double Longitude { get; set; } ///  /// ... /// /// A value within a range -90 and 180 ///  public double Latitude { get; set; } } 

必须测试所有相关模块以符合其依赖性的规范。 测试驱动开发是一种方式。 合同驱动的发展是另一个。

如果你坚持使用运行时检查值进行“defencive编程”,那么只需使用构造函数

 public class Position { ///  /// ... /// /// A value within a range -180 and 180 ///  public double Longitude { get; private set; } ///  /// ... /// /// A value within a range -90 and 180 ///  public double Latitude { get; private set; } public Position(double longitude, double latitude) { if (longitude < -180 || longitude > 180) { throw new ArgumentOutOfRangeException(); } if (latitude < -90 || latitude > 90) { throw new ArgumentOutOfRangeException(); } Longitude = longitude; Latitude = latitude; } } 

或使用建设者

 public class Position { public double Longitude { get; private set; } public double Latitude { get; private set; } ///  /// Protects from invalid positions. Use  ///  private Position() { } ///  /// Builds valid positions ///  public class Builder { public double Longitude { get; set; } public double Latitude { get; set; } public Position Build() { if (Longitude < -180 || Longitude > 180) { throw new ArgumentOutOfRangeException(); } if (Latitude < -90 || Latitude > 90) { throw new ArgumentOutOfRangeException(); } return new Position() { Latitude = this.Latitude, Longitude = this.Longitude }; } } } 

用法:

 Position p = new Position.Builder() { Latitude = 2, Longitude = 5 }.Build(); 

摘要:

  • 运行时检查(“防御性编程”):
    • 公共二传手与支票(见其他答案)
    • 公共构造函数与检查
    • “构建器模式”与构建器执行检查
  • 测试时间检查:
    • 测试驱动
    • 合约驱动