为什么要为属性创建私有字段?

时间:2016-02-23 05:34:24

标签: c# properties c#-6.0

我已经查看了与字段相比的属性示例,我总是看到一个没有解释的事情是创建私有字段,然后创建属性。为什么我们需要_foo,并且不能只运行与我下面相似的代码,或者可以用Foo = Foo替换Foo = value

我在运行时看到它创建了一个堆栈溢出异常,所以我猜它正在寻找一个值来填充Foovalue,但我认为这将是当我def.Foo = 55时处理。

即使创建私有字段是最佳做法,我仍然希望更好地了解实际导致溢出的内容。

class ABC
{
    private int _foo; //Why create this?
    public int Foo
    {
        get { return Foo; }
        set
        {
            Foo = Foo;//more logic would go here. }
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        ABC def = new ABC();
        def.Foo = 55;
        Console.WriteLine($"The value of Foo is {def.Foo}.");
        Console.ReadLine();
    }
}

3 个答案:

答案 0 :(得分:1)

这是因为字段属性不一样。

private int _foo; //field
public int Foo //property
{
    get { return _foo; } //should be _foo
    set
    {
        _foo = value;
    }
}

通常,您使用公共财产来访问私有字段,因为您可能想要执行除分配/获取值之外的其他操作该领域。

示例:

private bool selectedIndexChanged; //note this additional field
public bool SelectedIndexChanged {
    get { return selectedIndexChanged; }
    set { selectedIndexChanged = value; }
}

private int selectedIndex; //Why create this?
public int SelectedIndex
{
    get { return selectedIndex; }
    set
    {
        selectedIndexChanged = value != selectedIndex; //you update selectedIndexChanged here!
        selectedIndex = value;
    }
}

请注意,您不直接访问私有字段,但可以通过公共属性访问它们。拥有属性的好处在于,您不仅可以读取/分配字段值,还可以执行其他内容:检查输入的有效性,分配其他字段,调用事件等等......

  

即使创建私有字段是最佳做法,我仍然会这样做   希望更好地了解实际造成的问题   溢出。

练习导致 错误 导致 溢出 >练习:

private int _foo; //Why create this?
public int Foo
{
    get { return Foo; } //this should not happen, wrong practice
    set
    {
        Foo = Foo; //neither should this happen, another wrong practice
    }
}

以上代码中发生的事情是:

  1. 你得到Foo,它返回Foo,你需要得到Foo,你需要得到Foo,它返回Foo,你需要得到Foo返回Foo,你需要得到Foo,它需要返回Foo,你需要得到Foo返回Foo,你需要得到Foo,它返回Foo你需要得到Foo返回Foo,你需要得到Foo,它返回Foo你需要得到Foo返回Foo,你需要得到Foo,哪个返回Foo你需要得到Foo返回Foo,你需要得到Foo,它返回Foo你需要得到Foo返回Foo,你需要得到Foo,它返回Foo你需要得到Foo返回Foo,你需要得到Foo,返回Foo,你需要得到Foo返回Foo,你需要得到Foo,返回Foo你需要得到Foo返回Foo,你需要得到Foo,它返回Foo你需要让Foo返回Foo,你需要得到Foo ......直到无穷大
  2. 同样地:

    1. 你设置Foo,需要得到返回Foo的Foo,你需要得到Foo,你需要得到Foo,返回Foo,你需要得到Foo返回Foo,你需要得到Foo,返回Foo你需要让Foo返回Foo,你需要得到Foo,它返回Foo,你需要得到Foo返回Foo,你需要得到Foo,它返回Foo你需要得到Foo返回Foo,你需要得到Foo,返回Foo,你需要得到Foo返回Foo,你需要得到Foo,返回Foo,你需要得到Foo返回Foo,你需要得到Foo,它返回Foo你需要得到Foo返回Foo,你需要得到Foo,它返回Foo,你需要得到Foo返回Foo,你需要得到Foo,它返回Foo,你需要得到Foo返回Foo,你需要得到Foo,返回Foo你需要得到Foo返回Foo,你需要得到Foo ......直到无穷大
    2. 因此导致溢出......

答案 1 :(得分:1)

  

为什么我们需要_foo,而且不能只运行类似于我的代码   有以下,或可能取代?

因为属性是方法,可以设置或获取字段的值。所以,你必须先定义一个字段。如果您必须在内部暗示任何逻辑,尤其是在setter中,则需要这样做。否则,使用自动实现的属性更为常见。

即使在我们使用自动实现属性的情况下,编译器也会为我们生成一个支持字段。

public Person
{
    public string FirstName { get; set; }
}

例如,这样做

var person = new Person { FirstName = "Bob" };

使用名为Person的属性创建一个新的FirstName对象,其类型为字符串。此外,您将人员FirstName的值设置为Bob。这是你必须要注意的一点。编译器会生成一个类型为string的后备字段,并且在运行时,这将是存储对该人的名字的引用的地方。

上述类的定义类似于以下类:

public Person
{
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; }
    }
}

实际上,当您定义自动实现的属性时,幕后的编译器是什么。基于此,我们可以说对字符串“Bob”的引用将存储到_firstName

答案 2 :(得分:0)

属性实际上是实际变量的get / set方法。但是,您并不总是需要私有变量来拥有一个属性。

你可以简单地拥有

public int Foo { get; set; }

编译器将为您创建和设置变量。 但是,如果您需要限制属性以获取分配的错误值或执行其他任务,则需要属性变量。

示例:

private int _score;
public int Score
{
    get { return _score; }
    set
    {
        if(value > 100)
            throw new Exception("Score cannot be more than 100");

        _score = value;
    }
}