C# 财产实施-Noob缺乏知识

C# 财产实施-Noob缺乏知识,c#,properties,C#,Properties,我相信这个问题以前已经回答过对不起,但我不能把我的问题浓缩成一个愚蠢的短语 我有一个Pt3类,它是一个3d笛卡尔点(x,y,z属性加上一些其他的好东西)。我使用Pt3类型作为RegionProvider类中的get/set属性值-用于Location和Normal Location属性很好,我不在乎如何设置属性: //Location set method 1 - sweet... RegionProvider Foo = new RegionProvider(); Foo.Location.x

我相信这个问题以前已经回答过对不起,但我不能把我的问题浓缩成一个愚蠢的短语

我有一个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);
不过,普通属性需要不同的行为。如果需要,我希望RegionProvider类将输入规范化为Normal属性,例如,如果调用方将“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,但这似乎是伪造的

值得一提的是,这是我的正常财产声明:

/// <summary>
/// Property for the objects normal
/// </summary>
public Pt3 Normal
{
    set
    {
        _normal = Bit555ModelCore.NormalizeVector(value);
        this.NotifyPropertyChanged("Normal");
    }
    get
    {
        return _normal;
    }
}
//
///法线对象的属性
/// 
公共Pt3正常
{
设置
{
_normal=位555ModelCore.NormalizeVector(值);
本条。NotifyPropertyChanged(“正常”);
}
收到
{
恢复正常;
}
}

为任何帮助提前欢呼。

如果Pt3是你的职业,移除setter,(X,Y,Z)或将其设置为私有。

如果Pt3是你的职业,移除setter,(X,Y,Z)或将其设置为私有。

假设
正常
位置
必须是相同的类型,Pt3可以具有简单的属性:

public bool CanSetXyz { get; }
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;
    }
}
对于
位置
,将此属性初始化为
true
。对于
Normal
,将其初始化为
false

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

public bool CanSetXyz { get; }
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;
    }
}
EDIT:一个可能更有用的示例,基类允许读取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;
    }
}

假设
Normal
Location
必须为同一类型,Pt3可以具有简单的属性:

public bool CanSetXyz { get; }
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;
    }
}
对于
位置
,将此属性初始化为
true
。对于
Normal
,将其初始化为
false

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

public bool CanSetXyz { get; }
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;
    }
}
EDIT:一个可能更有用的示例,基类允许读取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;
    }
}

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

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

这就是基本的行为方式,除了
允许设置X和Y,当人们尝试类似的事情时,会导致各种各样的问题

Foo.Bar.X += 10;
而不是

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

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

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

这就是基本的行为方式,除了
允许设置X和Y,当人们尝试类似的事情时,会导致各种各样的问题

Foo.Bar.X += 10;
而不是

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

我想说问题在于你关于“好东西”的说法

如果您决定要有一个向量类(您的Pt3),那么就这样使用它。定义“Normalize()”方法并显式使用它


不管怎样,这就是我的建议。

我想说问题在于你关于“好东西”的说法

如果您决定要有一个向量类(您的Pt3),那么就这样使用它。定义“Normalize()”方法并显式使用它


嗯,无论如何,这是我的建议。

我想你有两个选择:

  • 通过使整个类不可变,确保从不单独设置
    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
    是可变的,所以如果将其用于
    位置
    ,方法1仍然可以工作

    然后,您可以使用强制转换运算符在两种类型之间进行转换:隐式强制转换从
    Pt3Mutable
    转换为
    Pt3Immutable
    ,而显式强制转换则相反


  • 我认为你有两个选择:

  • 通过使整个类不可变,确保从不单独设置
    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
    是可变的,所以如果将其用于
    位置
    ,方法1仍然可以工作

    然后,您可以使用强制转换运算符在两种类型之间进行转换:隐式强制转换从
    Pt3Mutable
    转换为
    Pt3Immutable
    ,而显式强制转换则相反


  • 标准的.NET陷阱,绝不是同样的方式,alw