2012-07-22 63 views
2

我相信这已被回答之前抱歉,但我不能凝结我的问题,以一个googlable短语。物业实施 - Noob缺乏知识

我有一个Pt3类,这是一个3D笛卡尔点(x,y,z属性加上一些其他的好东西)。我使用Pt3类型作为RegionProvider类中的get/set属性值 - Location和Normal。

的位置属性是好的,我不在乎财产是如何设置的:

//Location set method 1 - sweet... 
RegionProvider Foo = new RegionProvider(); 
Foo.Location.x = 10; 
Foo.Location.y = 20; 
Foo.Location.z = 30; 

//Location set method 2 - also sweet... 
RegionProvider Foo2 = new RegionProvider(); 
Foo2.Location = new Pt3(10, 20, 30); 

的普通属性,虽然需要不同的行为。如果需要,我希望RegionProvider类将输入标准化为Normal属性。如果调用者将“正常”值设置为40,50,60,则RegionProvider类将归一化为0.4558,0.5698,0.66838(给出向量长度== 1)。如果主叫方将执行以下操作,一切都很酷...

//Normal set method A - sweet... 
Foo.Normal = new Pt3(40, 50, 60); 

...但如果如果他们做到这一点悲伤将接踵而至:

//Normal set method B - grief... 
Foo2.Normal.x = 40; 
Foo2.Normal.y = 50; 
Foo2.Normal.z = 60; 

...因为RegionProvider类将作为正常化每个元素都被设置。我想要做的是防止调用者看到Normal属性的x,y,z,所以他们被迫使用上面的方法'A'。

一个解决方案可能是不规范化属性设置,但规范化属性获取但这看起来像fakery。

对于它的价值,这是我的普通财产申报:提前任何帮助

/// <summary> 
/// Property for the objects normal 
/// </summary> 
public Pt3 Normal 
{ 
    set 
    { 
     _normal = Bit555ModelCore.NormalizeVector(value); 
     this.NotifyPropertyChanged("Normal"); 
    } 
    get 
    { 
     return _normal; 
    } 
} 

干杯....

+0

标准.NET陷阱,从来没有以同样的方式,总是同样的问题。 Normal属性是一个值类型,当您访问它时会得到一个副本。您将更新副本,而不是原件。样板的智慧是“不要改变结构”。 – 2012-07-22 22:47:59

+0

@HansPassant我不认为这个问题是关于struct的。这是关于不允许独立设置属性的属性。 – svick 2012-07-22 23:42:12

回答

0

我认为你有两个选择:

  1. 确保的Pt3性能决不会被使整个班级不变的独立设置:

    class Pt3 
    { 
        public Pt3(double x, double y, double z) 
        { 
         X = x; 
         Y = y; 
         Z = z; 
        } 
    
        public double X { get; private set; } 
        public double Y { get; private set; } 
        public double Z { get; private set; } 
    } 
    
  2. 有两个类:Pt3MutablePt3Immutable(或一些更好的名字)。 Pt3Immutable将是不可变的,所以你可以安全地使用它NormalPt3Mutable将是可变的,所以如果你用它Location,方法1,仍能正常工作。

    然后,您可以将演员操作员在两种类型之间进行转换:隐式投射从Pt3MutablePt3Immutable,并显式转换。

0

如果PT3是你的类,去掉制定者,(X,Y ,Z)或者将它们私人化。

0

假设NormalLocation必须是相同的类型,PT3可以有简单的属性:

public bool CanSetXyz { get; } 

对于Location,此属性初始化到true。对于Normal,请将其初始化为false

然后在每个X,Y和Z属性:

private int _x; 

public int X 
{ 
    get { return _x; } 
    set 
    { 
     if (!CanSetXyz) 
     { 
      throw new CantSetXyzException("Can't set X on a Normal point."); 
     } 
     _x = value; 
    } 
} 

如果他们不必是同一类型,你想使一个共同的基类与总是分享的内容之间,然后一个班级不会有X,Y和Z的安装人员,另一个班级会有公共安装人员。

实施例:

public abstract class BasePt3 
{ 
    protected int x; 
} 

public class LocationPt3 : BasePt3 
{ 
    public int X 
    { 
     get { return x; } 
     set { x = value; } 
    } 

    public LocationPt3(int _x) 
    { 
     x = _x; 
    } 
} 

public class NormalPt3 : BasePt3 
{ 
    public int X 
    { 
     get { return x; } 
    } 

    public NormalPt3(int _x) 
    { 
     x = _x; 
    } 
} 

编辑:甲或许更有用的例子,与所述基类允许X被读取:

public abstract class BasePt3 
{ 
    protected int x; 

    public int X 
    { 
     get { return x; } 
    } 
} 

public class LocationPt3 : BasePt3 
{ 
    public new int X 
    { 
     get { return x; } 
     set { x = value; } 
    } 

    public LocationPt3(int _x) 
    { 
     x = _x; 
    } 
} 

public class NormalPt3 : BasePt3 
{ 
    public new int X 
    { 
     get { return x; } 
    } 

    public NormalPt3(int _x) 
    { 
     x = _x; 
    } 
} 
0

Pt3也许应该是一个结构,并作为不可变值处理。

取下制定者,只允许通过构造函数坐标的设定。那么你的类型的用户将不能够在同一时间改变一个属性当的Normal值已改变RegionProvider将永远知道。

这是非常如何System.Drawing.Point的行为,除了Point允许X和Y是造成各种问题,使人们在试图像

Foo.Bar.X += 10; 

,而不是

Foo.Bar += new Size(10, 0); 
+0

为什么它应该是'struct'? – svick 2012-07-22 23:44:20

+0

我认为它应该是一个结构,因为我希望表示一个点的类型像一个值一样,是不可变的,并通过复制传递。我可能受BCL定义点和相关类型为结构的影响。 – 2012-07-23 01:21:07

0

我会的东西说问题在于你对'好东西'的陈述。

如果你决定,你想有一个载体类(您PT3),使用它作为这样。定义'Normalize()'方法并明确使用它。

嗯,这是我的意见,无论如何。