Getters、setters 和 properties 最佳实践。Java vs. C#

2022-08-31 10:09:47

我现在正在上C#课,我试图找出最好的做事方式。我来自Java背景,所以我只熟悉Java最佳实践;我是 C# 新手!

在Java中,如果我有私有财产,我会这样做;

private String name;

public void setName(String name) {
   this.name = name;
}

public String getName() {
   return this.name;
}

在C#中,我看到有很多方法可以做到这一点。

我可以像Java一样做到这一点:

private string name;

public void setName(string name) {
   this.name = name;
}

public string getName() {
   return this.name;
}

或者我可以这样做:

private string name;

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

艺术

public string Name { get; set; }

我应该使用哪一种方法,每种方法涉及哪些警告或微妙之处?在创建类时,我遵循我从Java中了解的一般最佳实践(特别是阅读有效的Java)。例如,我赞成不可变性(仅在必要时提供 setter)。我只是好奇这些实践如何适应在C#中提供setter和getter的各种方式;从本质上讲,如何将Java世界的最佳实践转化为C#?

编辑

我发布这篇文章作为对Jon Skeet答案的评论,但后来它变得很长:

那么非平凡的属性(即,可能具有重要的处理和验证)呢?我是否仍可以通过公共属性公开它,但将逻辑封装在 和 中?为什么我会/应该这样做,而不是有专用的 setter 和 getter 方法(具有相关的处理和验证逻辑)。getset


答案 1

C# 6 之前的版本

我会用其中的最后一个,作为一个微不足道的属性。请注意,我将其称为公共属性,因为 getter 和 setter 都是公共的。

对于自动实现的属性,不可变性有点痛苦 - 你不能写一个只有getter的自动属性;最接近你的是:

public string Foo { get; private set; }

这并不是成不变的...只是在你的课堂之外不可变。因此,您可能希望改用真正的只读属性:

private readonly string foo;
public string Foo { get { return foo; } }

你绝对不想写和.在某些情况下,编写 Get/Set 方法而不是使用属性是有意义的,特别是如果它们可能很昂贵,并且您希望强调这一点。但是,您可能希望遵循PascalCase方法的.NET命名约定,并且无论如何都不希望使用普通方法实现像这样的平凡属性 - 这里的属性更加惯用。getName()setName()

C# 6

万岁,我们终于有了正确的只读自动实现属性:

// This can only be assigned to within the constructor
public string Foo { get; }

同样,对于确实需要执行一些工作的只读属性,可以使用成员主体属性:

public double Area => height * width;

答案 2

如果您只需要一个变量来存储一些数据:

public string Name { get; set; }

想要使其显示为只读?

public string Name { get; private set; }

甚至更好...

private readonly string _name;

...

public string Name { get { return _name; } }

想要在分配属性之前进行一些值检查?

public string Name 
{
   get { return m_name; }
   set
   {
      if (value == null)
         throw new ArgumentNullException("value");

      m_name = value;
   }
}

一般来说,GetXyz()和SetXyz()只在某些情况下使用,你只需要在感觉正确的时候使用你的直觉。总的来说,我会说我希望大多数 get/set 属性不包含很多逻辑,并且几乎没有任何意外的副作用。如果读取属性值需要调用服务或从用户获取输入以构建我正在请求的对象,那么我会将其包装到一个方法中,并将其称为 ,而不是 。BuildXyz()GetXyz()