C# 属性是隐藏实例变量还是更深层次的事情

本文关键字:深层次 变量 属性 隐藏 实例 | 更新日期: 2023-09-27 18:36:32

考虑类:

public class foo
{
    public object newObject
    {
        get
        {
            return new object();
        }
    }
}

根据MSDN:

属性是提供灵活读取机制的成员,写入或计算私有字段的值。可以使用属性好像他们是公共数据成员,但实际上他们很特殊称为访问器的方法。这使得数据能够轻松访问

和:

属性使类能够公开获取和设置值,同时隐藏实现或验证码。

get 属性访问器用于返回属性值,而set 访问器用于分配新值。这些访问器可以具有不同的访问级别。有关详细信息,请参阅访问器可及性。

value 关键字用于定义由设置索引器。

不实现 set 方法的属性是只读的。同时仍然提供方法的安全性和灵活性。

因此,这是否意味着在某个时间点,newObject 属性的值具有对返回的新对象的引用?

编辑从属性中删除的只读内容

edit2 还想澄清一下,这不是属性的最佳用途,但它是为了尝试更有效地说明问题。

C# 属性是隐藏实例变量还是更深层次的事情

每次访问属性时都会返回一个新对象,这不是属性的预期行为。相反,您应该每次都返回相同的值(例如,存储在字段中的值)。属性 getter 只是返回值的方法的美化语法。您的代码编译成这样的东西(编译器通过在属性名称前面加上 get_ 来创建 getter,然后作为 IL 发出):

public class foo
{
    public object get_newObject()
    {
        return new object();
    }
}

每次调用 getter 都会创建一个foo不知道或有权访问的新对象。

因此,这是否意味着在某个时间点,newObject 属性的值具有对返回的新对象的引用?

不。


使用支持字段的属性:

class Foo {
  readonly Object bar = new Object();
  public Object Bar { get { return this.bar; } }
}

使用自动属性:

class Foo {
  public Foo() {
    Bar = new Object();
  }
  public Object Bar { get; private set; }
}

使用与公共字段相同的简单语法访问属性。但是,通过使用属性,您可以向 getter 和 setter 添加代码,允许您在 getter 中进行延迟加载或在 setter 中进行验证(以及更多)之类的操作。

在后台,您的属性将简单地调用一个名为 get_newObject() 的函数,如下所示:

public object get_newObject()
{
    return new object();
}

由于是这种情况,因此每次调用它时,它总是会返回一个新对象。

如果要保留对对象的引用,那么我建议您创建一个私有字段来保存数据,并让属性访问该字段,如下所示:

private object myObject;
public object newObject
{
    if(myObject == null)
    {
        myObject  = new object();
    }
    return myObject;
}

由于您的属性没有定义 set,并且您的字段是私有的,因此 newObject 基本上只在包含类之外

C# 中的属性是"语法糖"。属性的get块中的代码实际上放入隐藏get_PropertyName()方法中,set块放入隐藏set_PropertyName()方法中。对于您的代码,将创建以下方法:

public object get_newObject()
{
    return new object();
}

如果使用反射器或 ildasm查看已编译的程序集,则可以看到这些隐藏的方法。

使用该属性时,C# 编译器会将属性的任何"get"访问转换为 get_newObject() 方法的调用。举个例子:

如果您要编写以下内容:

var foo = new foo();
var aNewObject = foo.newObject;

编译器会将其转换为:

var foo = new foo();
var aNewObject = foo.get_newObject();

因此,在回答您的另一个问题时,当有人"获取"属性时返回的新创建的对象不会存储在您的 foo 实例中,调用方每次都会简单地获取一个新对象。

不完全是。属性只是语法糖,因此您不必编写访问器方法(如 Java)。

所以这个:

private int _myInteger;
public int MyInteger
{
    get { return _myInteger; }
    set { _myInteger = value; }
}

等价于此:

private int _myInteger;
public int GetMyInteger()
{
    return _myInteger;
}
public void SetMyInteger(int value)
{
   _myInteger = value;
}

它变得更好了,这也是等效的:

public int MyInteger { get; set; }