我刚刚编写了一个可变的Point
类,它在使用C#6的新功能时尝试关注these guidelines。
public class Point
{
public int X, Y;
public static Point Zero => new Point(0, 0);
public static Point Up => new Point(0, -1);
public static Point Down => new Point(0, 1);
public static Point Left => new Point(-1, 0);
public static Point Right => new Point(1, 0);
public Point(int x, int y)
{
X = x;
Y = y;
}
public static Point operator +(Point a, Point b) => new Point(a.X + b.X, a.Y + b.Y);
public static Point operator -(Point a) => new Point(-a.X, -a.Y);
public static Point operator -(Point a, Point b) => a + -b;
public override bool Equals(object o) => Equals(o as Point);
public bool Equals(Point p) => (X == p?.X) && (Y == p?.Y);
public override int GetHashCode() => X ^ Y;
public static implicit operator string(Point a) => $"Point({a.X}, {a.Y})";
public override string ToString() => this;
}
这段代码评估为false
Point.Zero == Point.Zero
我完全清楚为什么会这样做,但问题是它应该评估为假吗?它对我来说并不合适。我的Point
班级是否正确遵循指南?
编辑:我根本不知道它是否应该评估为假。我想知道人们认为它应该评估什么。
编辑2:如何判断某个类是否应该是可变的?
答案 0 :(得分:3)
==
除非被覆盖,否则不会自动调用equals。它将在其基类上调用object
运算符,在您的情况下,它只是==
。 object
上的Point
运算符使用引用相等性,因此您询问两个==
引用是否相等,在您的情况下它们不相同,因为您的静态方法每次都返回一个 new 实例。
因此:
它应该评估为假吗?
根据你如何撰写课程,是的,它应该。如果您不想希望评估为false,那么您需要更改内容。
我的Point类是否正确遵循指南?
您还没有覆盖Point
,因此它将使用默认行为,该行为遵循指南。如果您使==
不可变,则覆盖Point.Zero == Point.Zero
将是合适的。
如果您不想希望Equals
返回false,可以采用以下方法:
==
代替Zero
来暗示价值平等Up,
,Point
等的实例,并返回它们而不是创建新实例。struct
更改为Point
,默认情况下将使用值相等而不是引用相等。请注意,如果您将struct
更改为__asm__ __volatile__ (
"vldmia.64 %[data_addr]!, {d0-d1}\n\t"
"vmov.f32 q12, #0.0\n\t"
: [data_addr] "+r" (data_addr)
: : "q0", "q12");
for(int n=0; n<10; ++n){
__asm__ __volatile__ (
"vadd.f32 q12, q12, q0\n\t"
"vldmia.64 %[data_addr]!, {d0-d1}\n\t"
: [data_addr] "+r" (data_addr),
:: "q0", "q12");
}
,那么您也应该将其设为不可变。可变结构can be challenging to work with因为它们在传递时被复制。因此,如果更改属性值,则需要更改结构的副本的属性值。
答案 1 :(得分:1)
也许这会澄清。这段代码:
public static Point Zero => new Point(0, 0);
是否相当于此代码:
public static Point Zero
{
get { return new Point(0, 0); }
}
这里很明显,每次调用Point.Zero时都会创建一个新的Point实例。 ==运算符默认执行引用检查,因为它们是Point的两个单独实例,所以比较失败。
您可以覆盖==运算符,类似于覆盖+, - 运算符的方式:
public static bool operator ==(Point a, Point b) => a.X == b.X && a.Y == b.Y;
public static bool operator !=(Point a, Point b) => a.X != b.X || a.Y != b.Y;
答案 2 :(得分:1)
首先,Zero
属性每次访问时都会创建一个新点。所以当你比较这些时:
Point.Zero == Point.Zero
您实际上正在比较两个完全不同的实例!并且==
仅比较2点内存中的地址,这就是为什么它是错误的。
现在已经开始了,让我们看看我们如何才能实现 true !实际上有很多方法。
Equals
方法代替==
运算符==
运算符Point
结构化。 (注意:这将需要对现有的运算符重载进行一些更改,因为struct是值类型)我看到你想要我们的一些建议,不是吗?以下是一些:
HashCode
您的“常量”声明非常严重。我甚至不确定它们是否应该是常数。它应该是这样的,你知道:
private static Point zero = new Point(0,0); public static Point Zero { 得到{return zero;} }
或只是简单地说:
public static readonly Point Zero = new Point(0, 0);
Point
。毕竟这是一个“结构”。甚至System.Windows.Forms.Point
也是一个结构。