我正在寻找定义新类型并在C#中使用它的可能性,如下所示:
班级定义:
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
};
答案 0 :(得分:11)
您不一定需要新类型。您可以手动编写一个验证值的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;然后提供适当的构造函数和转换运算符。
答案 1 :(得分:7)
您最好添加System.ComponentModel.DataAnnotations并使用[Range],如下所示:
public class Position
{
[Range(-180, 180)]
public double Longitude { get; set; }
[Range(-90, 90)]
public double Latitude { get; set; }
}
答案 2 :(得分:7)
一种类型可能有点过分,但如果你想要一种类型,这是一个好的开始:
struct Double180 : IEquatable<Double180>
{
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<Double180>
会很好。
正如您所看到的,您知道它的起源,但您不知道它的结束位置。
其他答案所建议的setter验证器可能是一个更好的主意。
答案 3 :(得分:4)
使用double
并让设置者检查值:
private double _longitude;
public double Longitude
{
get
{
return _longitude;
}
set
{
if(value < -180 || value > 180)
{
throw new ArgumentException("value");
}
_longitude = value;
}
}
答案 4 :(得分:4)
向设置器添加验证步骤:
private double m_Latitude;
public double Latitude
{
get{return m_Latitude;}
set
{
if(value < -90 || value > 90) throw new ArgumentException("value");
m_Latitude = value;
}
}
请注意,当您提供属性的实现时,您需要添加一个成员变量来存储基础属性值。
答案 5 :(得分:1)
我基本上明白了:验证setter中的输入。在类型定义方面,似乎Structs是最好的。最后,我将在我的项目中使用以下内容。
public struct Coordinate
{
private readonly double _x;
private readonly double _y;
/// <summary>
/// Longitude
/// </summary>
public double X
{
get { return _x; }
}
/// <summary>
/// Latitude
/// </summary>
public double Y
{
get { return _y; }
}
/// <summary>
/// Initiates a new coordinate.
/// </summary>
/// <param name="x">Longitude [-180, 180]</param>
/// <param name="y">Latitude [-90, 90]</param>
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);
感谢大家的宝贵意见。
答案 6 :(得分:1)
我喜欢将文档作为系统的一部分:
public class Position
{
/// <summary>
/// ...
///
/// A value within a range -180 and 180
/// </summary>
public double Longitude { get; set; }
/// <summary>
/// ...
///
/// A value within a range -90 and 180
/// </summary>
public double Latitude { get; set; }
}
必须对所有相关模块进行测试,以符合其依赖关系的规范。 以测试为导向的开发是一种方式。 合同驱动开发是另一个。
如果你坚持使用运行时检查值进行“defencive编程”,那么只需使用构造函数:
public class Position
{
/// <summary>
/// ...
///
/// A value within a range -180 and 180
/// </summary>
public double Longitude { get; private set; }
/// <summary>
/// ...
///
/// A value within a range -90 and 180
/// </summary>
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; }
/// <summary>
/// Protects from invalid positions. Use <see cref="Position.Builder"/>
/// </summary>
private Position() { }
/// <summary>
/// Builds valid positions
/// </summary>
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();