【问题标题】:When to use Properties and Methods?何时使用属性和方法?
【发布时间】:2009-07-30 21:03:38
【问题描述】:

我是来自 C++ 的 .NET 世界的新手,我正在努力更好地理解属性。我注意到在 .NET 框架中,Microsoft 到处使用属性。使用属性而不是创建 get/set 方法有优势吗?是否有关于何时应使用属性的一般准则(以及命名约定)?

【问题讨论】:

    标签: c# .net coding-style


    【解决方案1】:

    它是纯语法糖。在后端,它被编译成普通的 get 和 set 方法。

    使用它是因为惯例,而且它看起来更好。

    一些准则是,当它有很高的抛出异常或出错的风险时,不要使用属性,而是使用显式的 getter/setter。但通常即便如此,它们也会被使用。

    【讨论】:

    • 这可能不是你的意思,但我支持“看起来更好”的部分。在约定之前(当我还是个菜鸟的时候!),我使用属性是因为 IntelliSense 图标看起来更酷。
    • 哈哈。但我们谈论的是方法与属性,而不是字段与属性。
    • 我不同意,属性为您提供了良好的抽象水平。它们不仅仅是语法糖。
    • 这是关于 Get()/Set() 与 getter/setter 的对比。不是领域与财产。 Get()/Set() 允许与 getter/setter 相同类型的抽象。
    【解决方案2】:

    属性获取/设置方法;简单地说,它将它们形式化为一个单一的概念(用于读取和写入),允许(例如)针对 属性 的元数据,而不是单个成员。例如:

    [XmlAttribute("foo")]
    public string Name {get;set;}
    

    这是一对 get/set 方法,但额外的元数据适用于两者。此外,IMO 还让它更易于使用:

    someObj.Name = "Fred"; // clearly a "set"
    DateTime dob = someObj.DateOfBirth; // clearly a "get"
    

    我们没有重复我们正在执行 get/set 的事实。

    另一个好处是它允许对属性(上面的“名称”)进行简单的双向数据绑定,而不依赖于任何魔术模式(编译器保证的模式除外)。

    【讨论】:

      【解决方案3】:

      有一整本书专门用来回答这类问题:Addison-Wesley 的框架设计指南。有关何时选择属性与方法的建议,请参阅第 5.1.3 节。

      这本书的大部分内容也可以在 MSDN 上找到,但我觉得把它放在我的桌子上很方便。

      【讨论】:

        【解决方案4】:

        考虑阅读Choosing Between Properties and Methods。它有很多关于 .NET 设计指南的信息。

        【讨论】:

        • 感谢您的链接,那篇文章很有帮助!
        【解决方案5】:

        属性获取/设置方法

        【讨论】:

          【解决方案6】:

          正如周围的人所解释的那样,设置属性和获取方法,但拥有它们的想法是让这些方法成为唯一使用私有值的方法(例如,处理验证)。

          所有其他逻辑都应该针对属性完成,但是在精神上使用可以作为操作(属性)左侧和右侧的值处理的东西总是更容易,甚至不必认为它是一种方法.

          我个人认为这是属性背后的主要思想。

          【讨论】:

            【解决方案7】:

            我一直认为属性是类的名词,而方法是动词......

            【讨论】:

              【解决方案8】:

              首先,命名约定是:使用 PascalCase 作为属性名,就像使用方法一样。此外,属性不应包含非常复杂的操作。这些应该保存在方法中。

              在 OOP 中,您可以将对象描述为具有属性和功能。您在设计课程时会这样做。考虑设计一辆车。功能的示例可能是移动某处或激活雨刷器的能力。在您的班级中,这些将是方法。属性是给定时刻车内乘客的数量。如果没有属性,您将有两种方法来实现该属性:

              公开一个变量:

              // class Car
              public int passengerCount = 4;
              
              // calling code
              int count = myCar.passengerCount;
              

              这有几个问题。首先,它并不是真正的车辆属性。您必须从 Car 类内部更新值以使其代表车辆的真实状态。其次,变量是公共的,也可以写入。

              第二种变体是使用的一种widley,例如。 G。在 Java 中,你没有 c# 中的属性:

              使用方法封装值,可能先执行一些操作。

              // class Car
              public int GetPassengerCount()
              {
                 // perform some operation
                 int result = CountAllPassengers();
              
                 // return the result
                 return result;
              }
              
              // calling code
              int count = myCar.GetPassengerCount();
              

              通过这种方式,您可以设法解决公共变量的问题。通过询问乘客人数,您可以确保获得最近的结果,因为您在回答之前重新计票。此外,您无法更改该值,因为该方法不允许这样做。但问题是,您实际上希望乘客数量是一个属性,而不是您的汽车的功能。

              第二种方法不一定是错误的,只是读起来不太对。这就是为什么一些语言包含使属性看起来像变量的方法,即使它们在幕后像方法一样工作。例如,Actionscript 还包括定义方法的语法,这些方法将以变量样式从调用代码中访问。

              请记住,这也会带来责任。调用用户会期望它表现得像一个属性,而不是一个函数。因此,如果只是询问汽车有多少乘客需要 20 秒才能加载,那么您可能应该将其打包在一个真实的方法中,因为调用者会期望函数花费比访问属性更长的时间。

              编辑: 我几乎忘了提及这一点:在设置变量之前实际执行某些检查的能力。只需使用公共变量,您基本上可以在其中写入任何内容。 setter 方法或属性让您有机会在实际保存之前对其进行检查。

              【讨论】:

                【解决方案9】:

                属性只是为您节省一些时间来编写与 get/set 方法一起使用的样板。

                话虽如此,很多 .NET 东西处理属性的方式不同——例如,Grid 会自动显示属性,但不会显示执行等效操作的函数。

                这很方便,因为您可以为不想显示的内容创建 get/set 方法,并为您希望显示的内容创建属性。

                【讨论】:

                  【解决方案10】:

                  编译器实际上为您定义的每个属性发出 get_MyProperty 和 set_MyProperty 方法。

                  【讨论】:

                    【解决方案11】:

                    虽然这不是一个硬性规定,而且正如其他人所指出的那样,属性是作为“幕后”的 Get/Set 对实现的——通常是属性表面封装/受保护的状态数据,而方法(又名过程或函数)做工作并产生工作的结果。

                    因此,这些方法通常会采用参数,这些参数可能只是消耗,但也可能以改变的状态返回,或者由于完成的工作而产生新的对象或值。

                    一般来说 - 如果您需要一种控制对数据或状态的访问的方法,那么属性允许以定义的、可验证和优化的方式进行访问(允许访问限制、范围和错误检查、在需求和一种避免冗余设置调用的方法)。

                    相比之下,方法会在内部和外部转换状态并产生新值,而不必产生可重复的结果。

                    当然,如果您发现自己在属性中编写过程或转换代码,那么您可能真的在编写方法。

                    【讨论】:

                      【解决方案12】:

                      另请注意,属性可通过反射获得。虽然方法也是如此,但属性代表了关于对象的“有趣的东西”。如果您尝试显示对象的属性网格(例如,Visual Studio 表单设计器之类的东西),则可以使用反射来查询类的属性,遍历每个属性,并询问对象以获取其属性。价值。

                      【讨论】:

                        【解决方案13】:

                        这样想,属性封装了您的字段(通常标记为私有),同时让您的开发人员可以设置或获取字段值。如果需要,您甚至可以在属性的 set 方法中执行例行验证。

                        【讨论】:

                          【解决方案14】:

                          属性不仅仅是语法糖——如果您需要创建对象-关系映射(Linq2SqlLinq2Entities),它们很重要,因为它们的行为就像变量一样,但可以隐藏对象关系映射(持久性)的实现细节。还可以在属性的 getter 中验证分配给它的值,并防止它分配不需要的值。

                          你不能用同样优雅的方法做到这一点。我认为最好用一个实际的例子来证明这一点。

                          在他的一篇文章中,Scott Gu 创建了使用“代码优先”方法映射到 Northwind 数据库的类。摘自 Scott 博客的一个简短示例(稍作修改,全文可在 Scott Gu 的博客here 阅读):

                          public class Product
                          {
                              [Key]
                              public int ProductID { get; set; }
                          
                              public string ProductName { get; set; }
                              public Decimal? UnitPrice { get; set; }
                              public bool Discontinued { get; set; }
                              public virtual Category category { get; set; }
                          }
                          
                          // class Category omitted in this example
                          
                          public class Northwind : DbContext
                          {
                              public DbSet<Product> Products { get; set; }
                              public DbSet<Category> Categories { get; set; }
                          }
                          

                          您可以使用实体集ProductsCategories 以及相关的类ProductCategory,就像它们是包含变量的普通对象一样:您可以读写它们,它们的行为就像普通变量一样。但是您也可以在 Linq 查询中使用它们,将它们持久化(将它们存储在数据库中并检索它们)。 注意还有使用annotations(C# 属性)来定义主键是多么容易(在本例中ProductIDProduct 的主键)。

                          虽然属性用于定义存储在数据库中的数据的表示,但在实体集类中定义了一些方法 > 控制持久性:例如,方法Remove() 将给定实体标记为已删除,而Add() 添加给定实体,SaveChanges() 使更改永久化。您可以将方法视为操作(即您可以控制要对数据执行的操作)。

                          最后我给你一个例子,你可以多么自然地使用这些类:

                          // instantiate the database as object
                          var nw = new NorthWind();
                          
                          // select product
                          var product = nw.Products.Single(p => p.ProductName == "Chai");
                          
                          // 1. modify the price
                          product.UnitPrice = 2.33M;
                          
                          // 2. store a new category
                          var c = new Category();
                          c.Category = "Example category";
                          c.Description = "Show how to persist data";
                          nw.Categories.Add(c);
                          
                          // Save changes (1. and 2.) to the Northwind database
                          nw.SaveChanges();
                          

                          【讨论】:

                            猜你喜欢
                            • 2016-07-18
                            • 1970-01-01
                            • 2010-12-23
                            • 2013-11-06
                            • 2011-06-07
                            • 2017-10-09
                            • 1970-01-01
                            • 2010-10-10
                            • 1970-01-01
                            相关资源
                            最近更新 更多