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); } }
当然,还有更多的接口要实现,例如IConvertible
和IComparable
会很好。
正如您所看到的,您知道它从哪里开始,但您不知道它的结束位置。
如其他答案所示,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();
摘要:
- 运行时检查(“防御性编程”):
- 公共二传手与支票(见其他答案)
- 公共构造函数与检查
- “构建器模式”与构建器执行检查
- 测试时间检查:
- 测试驱动
- 合约驱动