代码之家  ›  专栏  ›  技术社区  ›  Dr. Watson

何时使用属性和方法?

  •  12
  • Dr. Watson  · 技术社区  · 17 年前

    我对来自.c++的.NET世界是新的,我正在尝试更好地理解属性。我注意到在.NET框架中,微软到处使用属性。使用属性而不是创建get/set方法是否有好处?对于何时应该使用属性,是否有一个通用的准则(以及命名约定)?

    14 回复  |  直到 13 年前
        1
  •  12
  •   Dykam    17 年前

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

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

    一些指导原则是,当它具有抛出异常或出错的高风险时,不要使用属性,而是使用显式的getter/setter。但一般情况下,即使使用了它们。

        2
  •  7
  •   Marc Gravell    17 年前

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

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

    这是一对get/set方法,但附加的元数据同时适用于这两种方法。而且,在我看来,它更容易使用:

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

    我们还没有复制我们正在做一个get/set的事实。

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

        3
  •  6
  •   Eric Lippert    17 年前

    有一整本书专门回答这些问题: 框架设计指南 来自艾迪生·韦斯利。有关何时选择属性与方法的建议,请参见第5.1.3节。

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

        4
  •  4
  •   Brandon    17 年前

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

        5
  •  2
  •   Steven A. Lowe    17 年前

    性质 获取/设置方法

        6
  •  2
  •   Alpha    17 年前

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

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

    我个人认为这是房地产背后的主要想法。

        7
  •  2
  •   Dan Diplo    17 年前

    我一直认为属性是一个类的名词,其中as-methods是动词…

        8
  •  2
  •   galaktor    16 年前

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

    在OOP中,您将对象描述为具有属性和功能。你在设计课程的时候就这么做了。考虑设计一辆汽车。功能性的例子可能是移动某个地方或激活雨刮器的能力。在您的类中,这些是方法。一个属性是给定时刻车内乘客的数量。如果没有属性,您将有两种方法来实现属性:

    公开变量:

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

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

    第二个变体是一个使用的Wistle,例如在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
  •  1
  •   Larry Watanabe    17 年前

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

    也就是说,许多.NET材料处理属性的方式不同——例如,网格将自动显示属性,但不会显示具有同等功能的函数。

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

        10
  •  0
  •   Darin Dimitrov    17 年前

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

        11
  •  0
  •   Gordon Mackie JoanMiro    17 年前

    尽管这不是一个硬性和快速的规则,而且正如其他人指出的那样,属性是作为“幕后”的get/set对来实现的——通常属性是表面封装/保护的状态数据,而方法(也称为过程或函数)确实起作用,并产生该工作的结果。

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

    一般来说-如果您需要一种控制数据或状态访问的方法,那么属性允许以定义的、可验证的和优化的方式访问的实现(允许访问限制、范围和错误检查、按需创建备份存储以及避免冗余设置调用)。

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

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

        12
  •  0
  •   Paul Williams    17 年前

    还请注意,属性通过反射可用。虽然方法也是,但属性表示关于对象的“有趣的东西”。如果您试图显示一个对象的属性网格(例如,类似于Visual Studio窗体设计器),那么您可以使用反射来查询类的属性,遍历每个属性,并询问对象的值。

        13
  •  0
  •   Steve    17 年前

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

        14
  •  0
  •   Matt    13 年前

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

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

    在他的一篇文章中,ScottGu创建了使用“代码优先”方法映射到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; }
    }
    

    可以使用实体集 Products , Categories 以及相关的课程 Product Category 就像它们是包含变量的普通对象一样:您可以读写它们,它们的行为就像普通变量一样。但您也可以在LINQ查询中使用它们,对它们进行持久化(将它们存储在数据库中并检索它们)。 注释 使用起来也很容易 annotations (c属性)定义主键(在本例中) ProductID 是的主键 产品 )

    性质 用于定义存储在数据库中的数据的表示,有一些 方法 定义在 实体集类 它控制持久性:例如,方法 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();
    
    推荐文章