102

我现在正在上 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)。因此,例如,我赞成不变性(仅在必要时提供设置器)。我只是想知道这些实践如何与 C# 中提供 setter 和 getter 的各种方式相适应;本质上,我如何将 Java 世界的最佳实践转化为 C#?

编辑

我将其发布为对 Jon Skeet 答案的评论,但后来它变得很长:

那么一个重要的属性(即,可能有重要的处理和验证)呢?我是否仍然可以通过公共属性公开它,但将逻辑封装在getand中set?为什么/应该通过专用的 setter 和 getter 方法(具有相关的处理和验证逻辑)来执行此操作。

4

12 回答 12

96

前 C# 6

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

不变性对于自动实现的属性来说有点麻烦——你不能写一个只有 getter 的自动属性;你能来的最接近的是:

public string Foo { get; private set; }

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

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

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

C# 6

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

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

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

public double Area => height * width;
于 2011-02-09T18:21:01.007 回答
17

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

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().

于 2011-02-09T18:34:21.377 回答
13

在 C# 中使用属性,而不是 get/set 方法。它们在那里是为了您的方便,而且是惯用的。

至于您的两个 C# 示例,一个只是另一个的语法糖。如果您只需要一个简单的实例变量包装器,请使用 auto 属性,当您需要在 getter 和/或 setter 中添加逻辑时,请使用完整版本。

于 2011-02-09T18:21:53.047 回答
5

在 C# 中,支持公开私有字段以获取和/或设置的属性。您提到的表单是一个自动属性,其中 get 和 set 会自动为您生成一个隐藏的枢轴支持字段。

如果可能,我更喜欢自动属性,但你永远不应该在 C# 中使用 set/get 方法对。

于 2011-02-09T18:22:38.703 回答
5
public string Name { get; set; }

这只是一个自动实现的属性,在技术上与普通属性相同。编译时将创建一个支持字段。

所有的属性最终都会转换为函数,所以最终实际编译的实现和你在 Java 中习惯的一样。

当您不必对支持字段执行特定操作时,请使用自动实现的属性。否则使用普通属性。当操作有副作用或计算量大时使用 get 和 set 函数,否则使用属性。

于 2011-02-09T18:22:50.887 回答
4

无论您在 C# 中选择哪种方式,最终结果都是相同的。您将获得一个带有单独的 getter 和 setter 方法的支持变量。通过使用属性,您将遵循最佳实践,因此您想要获得的详细程度是一个问题。

我个人会选择自动属性,最后一个版本:public string Name { get; set; },因为它们占用的空间最少。如果您需要添加验证等内容,您可以随时扩展这些内容。

于 2011-02-09T18:20:55.070 回答
4

只要有可能,我更喜欢 public string Name { get; set; },因为它简洁易读。但是,有时可能需要这个

private string name;

public string Name {
   get { return name; }
   set { name = value; }
}
于 2011-02-09T18:22:24.710 回答
4

在 C# 中,首选方式是通过属性而不是getX()setX()方法。另外,请注意,C# 不要求属性同时具有 get 和 set - 您可以具有 get-only 属性和 set-only 属性。

public boolean MyProperty
{
    get { return something; }
}

public boolean MyProperty
{
    set { this.something = value; }
}
于 2011-02-09T18:23:29.340 回答
4

首先让我试着解释一下你写的:

// private member -- not a property
private string name;

/// public method -- not a property
public void setName(string name) {
   this.name = name;
}

/// public method -- not a property
public string getName() {
   return this.name;
}

// yes it is property structure before .Net 3.0
private string name;
public string Name {
   get { return name; }
   set { name = value; }
}

这种结构现在也被使用,但如果你想做一些额外的功能,它最适合,例如,当一个值被设置时,你可以解析它以将其大写并将其保存在私有成员中以供更改内部使用。

使用 .net 框架 3.0

// this style is introduced, which is more common, and suppose to be best
public string Name { get; set; }

//You can more customize it
public string Name
{
    get;
    private set;    // means value could be set internally, and accessed through out
}

祝你在 C# 中好运

于 2011-02-09T18:31:12.690 回答
3

如前所述,所有这些方法都会产生相同的结果。最重要的是你选择一个约定并坚持下去。我更喜欢使用最后两个属性示例。

于 2011-02-09T18:23:19.537 回答
2

像这里的大多数答案一样,使用自动属性。直观,更少的代码行,更干净。如果你应该序列化你的类,用属性标记类[Serializable]/ 。[DataConract]如果您使用[DataContract]标记成员

[DataMember(Name="aMoreFriendlyName")]
public string Name { get; set; }

私人或公共二传手取决于你的喜好。

另请注意,自动属性需要 getter 和 setter(公共或私有)。

/*this is invalid*/
public string Name 
{ 
    get; 
   /* setter omitted to prove the point*/
}

或者,如果您只想获取/设置,请自己创建一个支持字段

于 2011-02-09T18:39:06.147 回答
0

我应该使用哪一个,每种方法有哪些注意事项或微妙之处?

使用属性时,有一个警告尚未提及:使用属性,您不能对 getter 或 setter 进行任何参数化。

例如,假设您想检索一个列表项,同时还想应用一个过滤器。使用 get 方法,您可以编写如下内容:

obj.getItems(filter);

相反,对于一个属性,您必须首先返回所有项目

obj.items

然后在下一步中应用过滤器,或者您必须添加专用属性来公开按不同条件过滤的项目,这很快就会使您的 API 膨胀:

obj.itemsFilteredByX
obj.itemsFilteredByY

有时可能会令人讨厌的是,当您开始使用属性时,例如obj.items,后来发现需要 getter 或 setter 参数化,或者会使类 API 用户的事情变得更容易。您现在需要重写您的 API 并修改代码中访问此属性的所有位置,或者找到替代解决方案。相反,使用 get 方法,例如obj.getItems(),您可以简单地扩展您的方法的签名以接受可选的“配置”对象,例如obj.getItems(options),无需重写所有调用您的方法的地方。

话虽如此,C# 中的(自动实现的)属性仍然是非常有用的快捷方式(出于此处提到的各种原因),因为大多数时候可能不需要参数化 - 但这个警告仍然存在。

于 2018-11-28T09:28:46.703 回答