2

我确定在抱歉之前已经回答了这个问题,但我无法将我的问题浓缩为可谷歌搜索的短语。

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

Location 属性很好,我不在乎属性是如何设置的:

//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”。

一种解决方案可能是根本不规范化属性集,而是规范化属性获取,但这似乎是伪造的。

对于它的价值,这是我的 Normal 属性声明:

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

提前欢呼任何帮助....

4

5 回答 5

0

如果 Pt3 是您的班级,请删除设置器 (X, Y, Z) 或将它们设为私有。

于 2012-07-22T22:33:49.813 回答
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 的设置器,并且其他人会有公共二传手。

例子:

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;
    }
}
于 2012-07-22T23:02:57.700 回答
0

Pt3应该可能是一个结构并被视为一个不可变的值。

删除设置器,只允许通过构造函数设置坐标。这样,您类型的用户将无法一次更改一个属性,并且RegionProvider始终知道 的值何时Normal更改。

这几乎就是System.Drawing.Point的行为方式,除了Point允许设置 X 和 Y 时,当人们尝试类似的事情时会导致各种问题

Foo.Bar.X += 10;

代替

Foo.Bar += new Size(10, 0);
于 2012-07-22T23:18:21.747 回答
0

我想说问题在于你关于“好东西”的陈述。

如果您决定要拥有一个矢量类(您的 Pt3),请使用它。定义“Normalize()”方法并明确使用它。

好吧,无论如何,这将是我的建议。

于 2012-07-22T23:37:29.277 回答
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将是不可变的,因此您可以Normal安全地使用它。Pt3Mutable将是可变的,因此如果您将其用于Location,方法 1 仍然有效。

    然后,您可以使用转换运算符在两种类型之间进行转换:隐式转换 from Pt3MutabletoPt3Immutable和显式转换相反。

于 2012-07-22T23:52:49.420 回答