财产实施 - Noob缺乏知识

时间:2012-07-22 22:23:36

标签: c# properties

我确信在对不起之前已经回答了这个问题,但是我不能将我的问题浓缩成一个可混淆的短语。

我有一个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;
    }
}

提前为任何帮助干杯....

5 个答案:

答案 0 :(得分:0)

如果Pt3是您的班级,请移除设置者,(X,Y,Z)或将其设为私有。

答案 1 :(得分: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的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)

我认为你有两个选择:

  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的隐式转换和显式转换。