在另一个属性设置器中使用属性值

时间:2013-06-05 09:32:32

标签: c# properties .net-3.5

在我的Class中,我需要根据另一个设置一个property值:

public class Quantities
{
    private int _quant;
    public int Quant
    {
        get { return _quant; }
        set
        {
            if (Unit == "K")
            {
                _quant = value / 1000;
            }
            else
            {
                _quant = value;
            }
        }
    }
    public string Unit { get; set; }
}

根据几项测试,我认为它工作正常,但我仍然不知道这样做是否安全 是Quant Property是否有可能在Unit Property之前进行评估,或者编译器(或JIT)是否知道它应该首先分配Unit Property

3 个答案:

答案 0 :(得分:8)

这与编译器或JIT无关。 您的代码会分配值。 需要知道应该分配的顺序。

顺便说一句:您的代码展示了temporal coupling。最好通过创建属性Unit并提供需要该单元的构造函数来使至少readonly不可更改:

public class Quantities
{
    private readonly string _unit;
    private int _quant;

    public Quantities(string unit)
    {
        if(unit == null) throw new ArgumentNullException("unit");
        _unit = unit;
    }

    public int Quant
    {
        get { return _quant; }
        set
        {
            if (Unit == "K")
            {
                _quant = value / 1000;
            }
            else
            {
                _quant = value;
            }
        }
    }
    public string Unit { get { return _unit; } }
}

现在不能以错误的方式使用此类。

有关可以通过课程改进的更多积分,请参阅Lasse's answer

答案 1 :(得分:6)

此课程外部的代码必须知道此依赖关系,否则您可能会有人更改Unit而无需重新设置Quant

var x = new Quantities(); // why no constructor for this?
x.Unit = "K";
x.Quant = 1700;           // why int? this will now be 1, not 1.7
x.Unit = "M";

我个人我会让这个类成为一个结构,并使它成为不可变的:

public struct Quantity
{
    private readonly double _Value;
    private readonly string _Unit;

    public Quantity(double value, string unit)
    {
        _Value = value;
        _Unit = unit;
    }

    public double Value
    {
        {
            return _Value;
        }
    }

    public double Unit
    {
        {
            return _Unit;
        }
    }
}

另请注意,我根本没有更改该值,因此:

var x = new Quantity(1700, "K");

表示1700K,而不是1.7K。我不会对数据进行这种“自动化”解释。如果您需要使用不同的单位显示值,我会建立一个转换系统:

    public Quantity ConvertToUnit(string newUnit)
    {
        var newValue = ... calculate value with new unit
        return new Quantity(newValue, newUnit);
    }

答案 2 :(得分:2)

班级不是一个好的设计。不要这样做。

请考虑以下代码:

Quantities q1 = new Quantities { Unit = "K", Quant = 1000};
Console.WriteLine(q1.Quant); // Prints 1

// Make a copy of q1

Quantities q2 = new Quantities{ Unit = q1.Unit, Quant = q1.Quant };
Console.WriteLine(q2.Quant); // Prints 0

您可以通过执行如上所述的基本复制来制作数量副本。它没有告诉你这种设计有多危险。

在上面接受的答案中进行更改后仍然存在问题

如果您使用Daniel建议的更改,您仍然会遇到与您的属性设置器相关的讨厌,并且getter不可交换。当然,您将被迫将单元传递给构造函数,但对象副本仍然无法按用户的预期工作:

Quantities q1 = new Quantities("K"){ Quant = 1000};
Console.WriteLine(q1.Quant); // Prints 1

// Make a copy of q1

Quantities q2 = new Quantities(q1.Unit){ Quant = q1.Quant };
Console.WriteLine(q2.Quant); // STILL Prints 0