《More effective C#》第二章 尽量采用隐式属性来表示可变的数据

简介: 《More effective C#》第二章 尽量采用隐式属性来表示可变的数据

考虑到读者的水平有高有低,照顾下新人,首先来解释下,什么是隐式属性,什么是显示属性

隐式属性是一种自动实现的属性,其中编译器会为属性生成相应的字段。隐式属性的语法更简单,只需要声明一个属性,而不需要显式声明一个对应的字段。例如:

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

在上面的示例中,Name 和 Age 属性都是隐式属性。编译器会自动为这些属性生成相应的字段。

显示属性是一种需要显式声明对应字段的属性。显示属性提供了更多的控制和保护,但语法更繁琐。例如:

public class Person
{
    private string name;
    private int age;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }
    public int Age
    {
        get { return age; }
        set { age = value; }
    }
}

在上面的示例中,Name 和 Age 属性都是显示属性。需要显式声明相应的字段,并在属性的 get 和 set 访问器中进行相应的操作。


总的来说,隐式属性比较方便,而且可以使代码更加简洁。但是,如果需要更多的控制和保护,或者需要自定义 get 和 set 访问器的行为,就需要使用显示属性。


C# 为属性提供了很多支持,允许通过属性清晰地表达出自己的设计思路,而且当前的 C# 语言还允许我们很方便地修改这些属性。如果你一开始就能采用属性来编写代码,那么以后便可以从容地应对各种变化。

在向类中添加可供访问的数据时,要实现的属性访问器通常很简单,只是对相应的数据字段做一层包装而已。在这种情况下,其实可以采用隐式写法来创建属性,从而令代码变得更加简洁:

  public string Name { get; set; }

编译器会生成一个名字来表示与该属性相对应的后援字段。可以用属性的 setter 修改这个后援字段的值。由于该字段是编译器生成的,因此,即便在自己所写的类中,也得通过属性访问器进行操作,而不是直接修改字段本身。这种区别其实并不会造成太大影响,因为编译器所生成的属性访问器中只包含一条简单的赋值语句,因此,很有可能得到内联,这样一来,通过属性访问器来操纵数据就和直接操纵后援字段差不多了。从程序运行时的行为来看,访问隐式属性与访问后援字段是一样的,就算从性能角度观察,也是如此。


扩充下面再来讲一下什么是后援字段:

C#中的后援字段(backing field)指的是在属性(property)内部用于存储属性值的变量。当我们声明一个属性时,实际上是声明了一个可以读写的公共接口,用于访问后援字段中的值。

例如,我们可以声明一个名为“Age”的属性:

public int Age { get; set; }


在这个属性声明中,我们没有显式地定义后援字段,但实际上编译器会自动创建一个名为“<Age>k__BackingField”的私有字段来存储Age属性的值。我们可以使用反编译工具来查看编译后的代码:

[CompilerGenerated]
private int <Age>k__BackingField;
public int Age
{
    [CompilerGenerated]
    get
    {
        return <Age>k__BackingField;
    }
    [CompilerGenerated]
    set
    {
        <Age>k__BackingField = value;
    }
}

在上面的代码中,我们可以看到编译器自动生成的后援字段和属性的定义。由于后援字段是私有的,因此无法直接访问,但我们可以通过公共的属性访问它的值。


在一些情况下,我们可能需要自定义后援字段的名称,例如:

private int _age;
public int Age 
{ 
    get { return _age; }
    set { _age = value; }
}

在这个例子中,我们使用名为“_age”的后援字段来存储Age属性的值,而不是使用编译器自动生成的后援字段。这种方式可以让我们更好地控制属性值的存储和访问,但也会增加代码的复杂度。因此,在大多数情况下,使用编译器自动生成的后援字段是更好的选择。

相关文章
|
7天前
|
开发框架 .NET Java
C#集合数据去重的5种方式及其性能对比测试分析
C#集合数据去重的5种方式及其性能对比测试分析
27 11
|
9天前
|
开发框架 .NET Java
C#集合数据去重的5种方式及其性能对比测试分析
C#集合数据去重的5种方式及其性能对比测试分析
38 10
|
15天前
|
存储 安全 编译器
学懂C#编程:属性(Property)的概念定义及使用详解
通过深入理解和使用C#的属性,可以编写更清晰、简洁和高效的代码,为开发高质量的应用程序奠定基础。
63 12
|
5月前
|
测试技术 API C#
C#使用Bogus生成测试数据
C#使用Bogus生成测试数据
62 1
|
3月前
|
SQL 缓存 分布式计算
C#如何处理上亿级数据的查询效率
C#如何处理上亿级数据的查询效率
51 1
|
4月前
|
安全 C# 索引
C#一分钟浅谈:属性与索引器的定义
本文深入浅出地介绍了C#编程中的属性和索引器。属性让字段更安全,通过访问器方法在读写时执行额外操作,如验证数据有效性;索引器则赋予类数组般的访问方式,支持基于索引的数据访问模式。文章通过示例代码展示了如何定义及使用这两种特性,并提供了常见问题及其解决方案,帮助读者写出更健壮、易维护的代码。希望读者能从中学习到如何有效利用属性和索引器增强C#类的功能性。
117 12
|
4月前
|
存储 C# 开发者
枚举与结构体的应用:C#中的数据组织艺术
在C#编程中,枚举(`enum`)和结构体(`struct`)是非常重要的数据类型。枚举用于定义命名常量集合,提高代码可读性;结构体则封装相关数据字段,适合小型数据集。本文从基本概念入手,探讨它们的使用技巧、常见问题及解决方案,帮助开发者更好地利用这些特性构建健壮的应用程序。
57 8
|
3月前
|
中间件 数据库连接 API
C#数据分表核心代码
C#数据分表核心代码
49 0
|
3月前
|
XML JSON 前端开发
C#使用HttpClient四种请求数据格式:json、表单数据、文件上传、xml格式
C#使用HttpClient四种请求数据格式:json、表单数据、文件上传、xml格式
665 0
|
5月前
|
存储 C# 数据库
解决C#对Firebase数据序列化失败的难题
在游戏开发中,Unity结合Firebase实时数据库为开发者提供强大支持,但在C#中进行数据序列化和反序列化时常遇难题。文章剖析了数据丢失或反序列化失败的原因,并给出解决方案,包括使用`JsonUtility`、确保字段标记为`[Serializable]`以及正确配置网络请求。示例代码演示了如何在Unity环境中实现Firebase数据的序列化和反序列化,并通过设置代理IP、Cookies和User-Agent来增强网络请求的安全性。这些技巧有助于确保数据完整传输,提升开发效率。
解决C#对Firebase数据序列化失败的难题