C# 编写不是容器的泛型类?[丙]
目标: 我一直在尝试用C编写一个通用的helper/utility类,它表示一个数字的边界检查范围 其思想是,用户可以通过定义最小值和最大值(例如,从0到10、从-15到3、从-7到-2等)来创建连续的数字范围。。该范围还包含一个当前值,并根据上限/下限检查该值。如果当前值大于最大值或小于最小值,则会将其覆盖或环绕。我希望这个类是泛型的,这样客户机就可以为他们的用例选择合适的类型/大小/精度 以下是我目前掌握的情况:C# 编写不是容器的泛型类?[丙],c#,generics,comparison,operator-overloading,operators,C#,Generics,Comparison,Operator Overloading,Operators,目标: 我一直在尝试用C编写一个通用的helper/utility类,它表示一个数字的边界检查范围 其思想是,用户可以通过定义最小值和最大值(例如,从0到10、从-15到3、从-7到-2等)来创建连续的数字范围。。该范围还包含一个当前值,并根据上限/下限检查该值。如果当前值大于最大值或小于最小值,则会将其覆盖或环绕。我希望这个类是泛型的,这样客户机就可以为他们的用例选择合适的类型/大小/精度 以下是我目前掌握的情况: public class Range<T> where T : I
public class Range<T> where T : IComparable<T> {
private T value;
private T min;
private T max;
private bool wrap;
public Range ( T minimumValue, T maximumValue, T initialValue, bool tempWrap = false ) {
value = initialValue;
min = minimumValue;
max = maximumValue;
wrap = tempWrap;
LimitBounds ();
}
private void LimitBounds () {
if( wrap != true ) {
if ( value > max ) { value = max; }
else if ( value < min ) { value = min ; }
}
else {
T wrapAmount = 0;
if ( value > max ) {
wrapAmount = value - max;
value = min + wrapAmount;
}
else if ( value < min ) {
wrapAmount = min - value;
value = max - wrapAmount;
}
}
}
public T GetValue() {
return value;
}
public void SetValue(T tempValue) {
value = tempValue;
LimitBounds ();
}
public void Increment() {
value++;
LimitBounds ();
}
public void Decrement() {
value--;
LimitBounds ();
}
public bool Equals(Range<T> tempRange)
{
return (value == tempRange.value);
}
public static bool operator > (Range<T> r1, Range<T> r2)
{
return (r1.value > r2.value);
}
public static bool operator < (Range<T> r1, Range<T> r2)
{
return (r1.value < r2.value);
}
public static Range<T> operator ++ ( Range<T> r ) {
r.Increment ();
return r;
}
public static Range<T> operator -- ( Range<T> r ) {
r.Decrement ();
return r;
}
}
。。我的大多数操作符重载都有类似的错误。我认为,如果我确保我的类处理的类型实现“Comparable”,则可以重载比较运算符。我显然做错了什么,但我不确定我需要做什么
如果它简化了事情,这个类实际上只需要处理纯数值/类型byte、short、int、float等
更新编辑1:
如下所示,通过切换到这些函数中的CompareTo,我能够消除由比较操作引起的一系列编译错误:
public bool Equals(Range<T> tempRange)
{
return (value.CompareTo(tempRange.value) == 0);
}
public static bool operator > (Range<T> r1, Range<T> r2)
{
return (r1.value.CompareTo (r2.value) > 0);
}
public static bool operator < (Range<T> r1, Range<T> r2)
{
return (r1.value.CompareTo (r2.value) < 0);
}
我还添加了“struct”约束。不过,我仍然不确定该从这里走到哪里。我的代码仍然无法编译,因为我一直在使用各种加法、减法、增量和减量运算符。我尝试添加byte、short、int和float作为附加的类型约束,但没有成功,这给了我一个编译时错误
我在这里有什么选择?因为这个类只处理数字的范围,基本上只处理各种大小的整数[字节、短、整数、长]和浮点小数,而不是可为null或引用类型,所以我可以使用其他约束来实现这一点吗?我是否必须围绕实现自定义“INumber”接口的基本数据类型创建一组包装器类
或者这是对泛型类的滥用,我应该为不同的类型创建一组独立的范围类?有可能生成一个实现我想要的行为类型的泛型类吗?错误的原因是编译器无法确保t的类型将正确地重载所有这些运算符。而且也没有这样的约束来强制它 例如,使用CompareTo方法代替比较运算符,而不是
value > max
使用
对于小于:value.CompareTomax<0的等式,value.CompareTomax==0
有关更多信息,请参阅文档
递增运算符和递减运算符更复杂。您可以为您的类型编写不同的重载以递增和递减,并为当前类型调用适当的重载
最后一点要注意的是,如果您计划将此方法仅用于byte、int、double等结构类型,则可能需要添加结构约束。对于泛型,您无法执行算术运算,因为直到编译时,您才知道其类型 所以你可以做两件事: 如果总是使用long、decimal等类型,那么将泛型类仅限于这些类型 运算符重载
这就是使用运算符和泛型的问题,因为很多代码无法编译。例如,value++或value-。编译器不知道t是否实现了特定的运算符。不幸的是,还没有对操作符的约束,所以您只剩下一些非常非通用的解决方案,或者您可以使用dynamic作为解决方案 请注意,这是绕过编译时检查。对于在运行时会中断的类型,您的代码可以很好地编译
public void Increment()
{
dynamic x = value;
x++;
value = x;
}
运算符不是虚拟的,因此不能与泛型类型一起使用。使用为受约束类型定义的适用方法。请记住,泛型不是模板,也不会发生文本替换。因此,代码必须对泛型类本身中由T表示的所有类型都有效。当您不知道类型时,如何在方法中执行value++和value-递增和递减?Duh!我懂了。。谢谢各位。最初我是用Short编写这个类的,但在我完成这项工作后,我决定让它更通用更有用/更灵活。我考虑过制作一些类,如“IntRange”、“ShortRange”、“FloatRange”等。我想当我弄明白后,这会好得多。我以前用过别人的仿制药,但这是我第一次尝试写一个我认为value.CompareTomax>1应该大于0。当然,如果T是引用类型,而value是空引用,它可能会爆炸。另一个解决方案是如果Comparer.Default.Comparevalue,max>0{…}。另一方面,如果您知道您不会将其用于引用类型,则可以
将constriant指定为其中T:struct,i可比较。关于平等,考虑是否平等不是你想要的方法。如果您限制为IEquatable,则在某些情况下可以避免装箱和类型检查,尽管它们非常快。谢谢大家的帮助。在添加约束并切换到CompareTo(在适用的情况下)之后,我成功地使通用比较工作起来!不幸的是,我仍然有大量的加法、减法、增量和减量操作会引发编译错误。。我还添加了一个结构约束。我可以使用不同的泛型约束来帮助获得+、-、++和-工作吗?或者尝试使用泛型来实现这类功能是不可能/不可取的吗?我应该放弃,只做一些特定的系列课程吗?ByteRange、IntRange、FloatRange等。。或者对我希望这个类处理的每种类型使用特定的约束?Byte、Short、Int、Float、Double等作为约束。@MrKatSwordfish它们应该有参数。像void Incrementref int i一样,您需要检查typeof T并将其传递给适当的函数cando。。操作员超载?谢谢。如果可能的话,我想避免这种情况;在可能的情况下,将运行时错误的风险降至最低似乎是个好主意。我更希望我的代码在编译时失败,而不是意外崩溃!:]我发现这比我想象的要困难得多。。haha@MrKatSwordfish理解。当我在项目中这样做时,我使用了结构约束和清晰的注释,以最大限度地减少误用的机会。
value.CompareTo(max) > 0
public void Increment()
{
dynamic x = value;
x++;
value = x;
}