struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
class MyClass
{
public Point Origin { get; set; }
}
MyClass c = new MyClass();
c.Origin.X = 23; //fails.
//but you could do:
c.Origin = new Point { X = 23, Y = c.Origin.Y }; //though you are invoking default constructor
//instead of
c.Origin = new Point(23, c.Origin.Y); //in case there is no constructor like this.
这是可能的,因为在幕后发生了这种情况:
Point tmp = new Point();
tmp.X = 23;
tmp.Y = Origin.Y;
c.Origin = tmp;
也就是说,如果您不需要在属性 get 和 set 方法后面编写代码(就像在您的示例中那样) ,那么简单地将 Origin声明为类的字段而不是属性不是更简单吗?我觉得这样你就能完成你的目标了。
struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
class MyClass
{
public Point Origin;
}
MyClass c = new MyClass();
c.Origin.X = 23; // No error. Sets X just fine
我觉得很多人都糊涂了,这个特殊问题涉及到理解值类型 < em > properties 返回值类型的一个副本(与方法和索引器一样) ,并且值类型 < em > 字段 被直接访问。下面的代码通过直接访问属性的后备字段完成了您想要完成的任务(注意: 使用后备字段以冗长的形式表示属性相当于 auto 属性,但是在我们的代码中,我们可以直接访问后备字段) :
class Program
{
static void Main(string[] args)
{
var myClass = new MyClass();
myClass.SetOrigin();
Debug.Assert(myClass.Origin.X == 10); //succeeds
}
}
class MyClass
{
private Point _origin;
public Point Origin
{
get => _origin;
set => _origin = value;
}
public void SetOrigin()
{
_origin.X = 10; //this works
//Origin.X = 10; // fails with CS1612;
}
}
您得到的错误是不理解属性返回值类型副本的间接后果。如果返回一个值类型的副本,并且没有将其赋值给局部变量,那么对该副本所做的任何更改都无法读取,因此编译器将其作为错误引发,因为这不是故意的。如果我们将副本分配给局部变量,那么我们可以改变 X 的值,但是它只会在局部副本上改变,这修复了编译时错误,但是不会产生修改 Origin 属性的预期效果。下面的代码说明了这一点,因为编译错误已经消失,但是调试断言将会失败:
class Program
{
static void Main(string[] args)
{
var myClass = new MyClass();
myClass.SetOrigin();
Debug.Assert(myClass.Origin.X == 10); //throws error
}
}
class MyClass
{
private Point _origin;
public Point Origin
{
get => _origin;
set => _origin = value;
}
public void SetOrigin()
{
var origin = Origin;
origin.X = 10; //this is only changing the value of the local copy
}
}