Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# OO设计-您在内部使用公共属性还是私有字段?_C#_Oop_Coding Style - Fatal编程技术网

C# OO设计-您在内部使用公共属性还是私有字段?

C# OO设计-您在内部使用公共属性还是私有字段?,c#,oop,coding-style,C#,Oop,Coding Style,我使用的是C#2.0,但这适用于大多数面向对象语言。当我创建带有封装私有字段的公共属性的类时,我会在是否应该在内部使用属性或字段之间来回切换。当然,C#3.0使自动属性更容易实现这一点,但它仍然可以应用 这有关系吗 public class Person { private string _name = ""; public string Name { get { return _name; } set { _name = value;

我使用的是C#2.0,但这适用于大多数面向对象语言。当我创建带有封装私有字段的公共属性的类时,我会在是否应该在内部使用属性或字段之间来回切换。当然,C#3.0使自动属性更容易实现这一点,但它仍然可以应用

这有关系吗

public class Person
{
    private string _name = "";

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    public Person(string name)
    {
        _name = name; //should I use the property or field here?
    }
}

大多数情况下,它类似于代码首选项,但我更喜欢使用公共属性或私有属性,您可以简单地向属性添加一些逻辑,而无需更改调用方代码。在3.5.NET中,您还可以使用有用的代码sugar作为自动属性。

我建议您使用该属性,因为您永远不知道何时可能在属性中执行某些操作,例如延迟加载、转换、格式化、计算,等。如果您使用私有成员,这将引入错误…

通常我使用公共属性,但有些例外情况下,我可能希望避免在属性访问器中写入任何额外代码。由于C#3.0中的自动属性,我很少手动创建支持字段;通常只有当自动备份字段的默认值不适合我的属性时,才使用公共字段。

至少在Java中,您不可能使用公共字段,因为大家似乎都在使用好的旧javabeans约定。
我想C#作为第一语言结构有其属性。我认为你应该使用“Name”(属性),因为如果你想检查这个值,你可以将它放入“Name”属性的setter中,然后将它用于构造函数和最近的设置值。

使用属性。或者更好的是,如果您使用的是C#3.0或更高版本,请使用以下自动属性:

public class Person
{
    public string Name { get; set; }

    public Person(string name)
    {
        Name = name; //should I use the property or field here?
    }
}

如果您现在使用该属性,那么当您修改代码以使用自动属性时,您就可以准备好了。

基本上,因为您可以在该属性中实现验证和其他逻辑,您应该通过该属性进行访问,除非您有特定的理由不这样做

它有助于对象内的一致性,因为这样您就知道私有字段的值已经经历了您选择放入访问器或设置器方法的任何严格过程

另一方面,构造函数可能是一个例外,因为您可能需要设置初始值

但总的来说,我会说通过财产进入

编辑

(琐碎的/人为的)例子

公共类人物
{
私有字符串_name=“”;
private List oldnames=new ArrayList();
公共字符串名
{
获取{return\u name;}
设置
{
oldnames.Add(_name);
_名称=值;
}
}
公众人物(字符串名称)
{
_name=name;//我应该在这里使用属性或字段吗?
}
}

因此,在这种情况下,您可能希望构造函数跳过该属性,但如果再次使用该字段,您将在代码中导致错误,因为您跳过了“名称存档”。将验证放在属性中的原因是,您不需要在访问字段的每个位置重复验证代码,因此即使在私有方法中也不应该跳过验证代码

视情况而定。有时,您将编写getter/setter,为与字段的任何实际交互执行重要的预处理。例如,如果字符串字段有一个必须始终为小写的约束,那么至少有一个getter/setter方法必须调用.ToLower()或.ToLowerInvariant(),并且在类代码中,您可能希望使用它来确保强制执行该约束

然而,有时也需要绕过预处理逻辑。事实上,我见过开发人员不经意间使用公共属性而不是私有字段创建无限循环的情况(对不起,我想不出一个现成的例子)

我认为Linq到SQL生成的类是一个很好的例子,因为它们显示了属性中可以存在多少逻辑。尝试编写一些扩展方法,您将开始理解其中的区别


我认为最重要的一点是,它取决于在类中的任何给定点使用什么样的逻辑,以及getter/setter中存在什么样的预处理。如果您不确定或似乎不重要,那么最好使用getters/setters/public属性,这样您就可以编写更多可维护的代码,这些代码将遵循稍后添加的约束。

有时您必须在内部访问该字段。例如,当您仅公开提供对属性的只读访问,而不提供在对象实例化后允许更改的值时

public class MyClass
{
    private string _MyProperty;

    public MyProperty { get { return _MyProperty; } }

    public MyClass ()
    {
        _MyProperty = SomeVeryComplexPropertyInitializationLogic ();
    }
}

如果使用字段名,则不会得到封装。封装不仅适用于类之间,而且适用于类内部

如果在将来的某个时刻,您重新定义了字段,但使accessor/setter函数的签名保持不变,那么不仅使用您的类的外部类不会中断,而且您自己的类中的内部例程也不会中断

以这段代码为例,松散地基于ApacheWicket框架中显示的代码(尽管框架没有遇到这个问题;我只是用它来说明):

假设这是原始类:

class RadioChoice {
  private String prefix;

  RadioChoice( String prefix ) {
    this.prefix = prefix ;

  setPrefix( String prefix )  {
    this.prefix = prefix ;
   }
}
这里我们已经看到了一个问题:相同的操作
this.prefix=prefix
发生在两个地方。它的本意是做完全相同的事情,但由于它发生在两个地方,“同一件事”可以分为两个不同的事情。(将此与数据库规范化进行比较,数据库规范化是一种旨在防止这种情况发生的做法。)

现在,ApacheWicket有了一个概念,即记录对如何呈现web页面的更改,以便可以撤消这些更改。它通过存储一个“undo”对象列表来实现这一点。RadioChoice的前缀是可以撤消的事情之一
class RadioChoice {
  private String prefix;

  RadioChoice( String prefix ) {
    this.prefix = prefix ;

  setPrefix( String prefix )  {
    this.prefix = prefix ;
   }
}
class RadioChoice {
  private String prefix;

  RadioChoice( String prefix ) {
    this.prefix = prefix ;

  setPrefix( String prefix )  {
    // save the old prefix
    this.getPage().addChange( new PrefixChange( this.prefix ) );
    // set the new one
    this.prefix = prefix ;
   }
}
  setPrefix( String prefix )  {
    // save the old prefix
    this.getPage().addChange( new PrefixChange( this.getPrefix() ) );
    // set the new one
    this.prefix = prefix ;
   }
}