4

变量、方法和类可以接收各种安全级别。根据我的 C# 经验,有:

公共
内部
受保护 受
保护 内部
私有

现在,我了解了将方法和类设为私有、内部或受保护的用途,但变量呢?即使我将变量设为私有,我也可以使用属性从不同的类中调用它。

我一直认为属性是最佳实践。所以如果我可以使用它,我不需要直接通过实例调用变量。

有什么理由不将变量设为私有吗?

编辑:我看到有些人在谈论属性,好像它们只不过是美化的公共变量

快速提醒:公共变量只返回它们的值。有了属性,您可以做更多事情。例如:

public int AmountOfBooks{
  get {
    //code to check certain conditions
    //maybe trigger an event while we're at it.
    //and a few conditionals.
    return this.amountOfBooks;
  }

  set {
    //a few conditionals
    //maybe trigger an event
    this.amountOfBooks = value;
    //and I can do even more... I think, never tried this.
  }
}

看过我简介的人都知道我是一名学生。使用属性作为“美化的公共变量”是我看到很多同学做的事情。告诉他们可以这样做时,最常见的反应是:“允许吗?”

4

8 回答 8

14

当然,在某些情况下,拥有一个公共领域是有意义的。例如,如果您创建一个结构只是为了与现有的非托管 win32 API 互操作。

但是,如果您正在构建常规托管对象模型,最佳实践是将对象的属性建模为属性,并使用字段作为私有实现公开公开功能的机制。

更新:我将借此机会指出,我们已尝试在 C# 3.0 中让编写一个简单地访问后备存储的属性变得非常容易:

public int Foo { get; set; }

完全一样

private int _Foo;
public int Foo { get { return _Foo; } set { _Foo = value; } }

但更短,更容易阅读。当然,如果您以后需要将其扩展为带有后备存储的长格式,这样做并不是一个重大变化。

你也可以这样做:

public int Foo { get; private set; }

如果您想为类/结构之外的代码创建一个只读属性。

于 2009-11-23T00:14:35.867 回答
6

如果在设置或获取变量时需要执行任何代码,或者如果您将来需要添加此类代码,涉及的 API 中存在任何不兼容的更改,则属性是最佳实践。

由于后一个子句,在语言中“抢先”使用访问器很可能是有意义的,否则会需要这种不兼容的更改(最著名的例子是Java中的getThis/约定)!setThis

但是,当您的语言允许您从公共变量切换到属性,反之亦然,而无需在 API 中进行任何不兼容的更改(例如 C#、Ruby、Python,...),当公共访问器(getter和 setter) 除了复制到私有变量和从私有变量复制之外什么都不做——即使你确定你的编译器可以优化它们,这样的样板访问器只会徒劳地膨胀源代码,并浪费一个重要的设计特性,它是构成这种语言的一部分不错的;-)

于 2009-11-23T00:20:41.757 回答
4

在我的脑海中,我能想到两个我会使用公共领域的地方

  1. 为程序集的使用者发布常量或只读值
  2. 部分基础设施(例如在 Workflow Foundation 中)迫使我这样做
于 2009-11-23T00:16:08.733 回答
0

例如,如果您有一个具有属性 id_code 的类。

如果属性是公共的,我可以用任何类型的值设置这个变量。

如果您将此 id_code 设为私有并创建一个设置方法,您可以制定有关 id_code 格式的规则。所以方法:

public setIdCode(String id) {
    my_attribute_id_code = "000"+id;
}

这是第一个简单的例子。

于 2009-11-23T00:15:18.737 回答
0

是的。例如,将字段标记为受保护允许它被派生类直接使用,派生类在概念上仍保持面向对象的理念。

不过,总的来说,你是对的。通常首选将类的字段标记为私有并将必要的字段公开为属性。这有助于诸如封装、字段验证和代码维护之类的事情。

于 2009-11-23T00:18:52.517 回答
0

在某些情况下,字段的处理方式与属性的处理方式不同。标准的序列化格式化程序(BinaryFormatter 和 SoapFormatter)将序列化字段,但不序列化属性。有时可能需要控制类型的序列化。

于 2009-11-23T17:37:18.897 回答
0

尚未提及的两个原因:

  1. 字段可以作为 ref 参数直接传递给方法。例如,可以在一个字段上调用“Interlocked.Increment”,例如,以线程安全的方式(假设该字段的其他用户也使用“Interlocked”例程来访问它)。将属性复制到局部变量,通过引用传递该变量,然后将变量复制回属性将产生不同的语义。
  2. 结构类型的字段可以比结构类型的属性更有效地访问和操作。事实上,与可变或大型结构相关的许多“问题”和低效率实际上源于属性假装是变量的事实,但实际上并非如此。

这并不意味着将事物公开为属性而不是字段没有优势,但字段确实具有明确的优势。

于 2012-05-01T16:33:34.130 回答
-2

如果您的财产Status属于以下性质:
public int Status {get; set;}

有些人可能只是使用:
public int Status;

于 2009-11-23T00:20:34.073 回答