我确信在对不起之前已经回答了这个问题,但是我不能将我的问题浓缩成一个可混淆的短语。
我有一个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);
Normal属性需要不同的行为。我希望RegionProvider类将输入规范化为Normal属性(如果需要,例如:如果调用者将“正常”值设置为40,50,60,则RegionProvider类将标准化为0.4558,0.5698,0.6838(以给出向量长度== 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'。
一种解决方案可能是根本不对属性集进行规范化,而是对属性get进行规范化,但这似乎是伪造的。
对于它的价值,这是我的Normal属性声明:
/// <summary>
/// Property for the objects normal
/// </summary>
public Pt3 Normal
{
set
{
_normal = Bit555ModelCore.NormalizeVector(value);
this.NotifyPropertyChanged("Normal");
}
get
{
return _normal;
}
}
提前为任何帮助干杯....
答案 0 :(得分:0)
如果Pt3是您的班级,请移除设置者,(X,Y,Z)或将其设为私有。
答案 1 :(得分:0)
假设Normal
和Location
必须属于同一类型,则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的setter ,另一个会有公共制定者。
示例:
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;
}
}
答案 2 :(得分:0)
Pt3
应该是一个结构并被视为不可变值。
删除setter,只允许通过构造函数设置坐标。您的类型的用户将无法一次更改一个属性,RegionProvider
将始终知道Normal
的值何时发生更改。
这几乎就是System.Drawing.Point行为的方式,除了Point
允许设置X和Y,当人们尝试像
Foo.Bar.X += 10;
而不是
Foo.Bar += new Size(10, 0);
答案 3 :(得分:0)
我想说问题出在你关于'好东西'的陈述中。
如果您决定要使用矢量类(您的Pt3),请使用它。定义'Normalize()'方法并明确使用它。
嗯,无论如何,这将是我的建议。
答案 4 :(得分:0)
我认为你有两个选择:
确保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; }
}
有两个类:Pt3Mutable
和Pt3Immutable
(或更好的名字)。 Pt3Immutable
将是不可变的,因此您可以安全地将其用于Normal
。 Pt3Mutable
是可变的,因此如果您将其用于Location
,方法1仍然可以使用。
然后你可以使用转换运算符在两种类型之间进行转换:从Pt3Mutable
到Pt3Immutable
的隐式转换和显式转换。