《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属性的值,而不是使用编译器自动生成的后援字段。这种方式可以让我们更好地控制属性值的存储和访问,但也会增加代码的复杂度。因此,在大多数情况下,使用编译器自动生成的后援字段是更好的选择。

相关文章
|
2月前
|
C# 数据库
c# dev Form1 gridview1使用Form2 gridview1的数据
c# dev Form1 gridview1使用Form2 gridview1的数据
|
2月前
|
开发框架 .NET C#
C#数据去重的这几种方式,你知道几种?
C#数据去重的这几种方式,你知道几种?
|
2月前
|
存储 安全 编译器
C# 11.0中的泛型属性:类型安全的新篇章
【1月更文挑战第23天】C# 11.0引入了泛型属性的概念,这一新特性为开发者提供了更高级别的类型安全性和灵活性。本文将详细探讨C# 11.0中泛型属性的工作原理、使用场景以及它们对现有编程模式的改进。通过深入了解泛型属性,开发者将能够编写更加健壮、可维护的代码,并充分利用C#语言的最新发展。
|
2月前
|
编译器 数据处理 C#
C#中的异步流:使用IAsyncEnumerable<T>和await foreach实现异步数据迭代
【1月更文挑战第10天】本文介绍了C#中异步流的概念,并通过使用IAsyncEnumerable<T>接口和await foreach语句,详细阐述了如何异步地迭代数据流。异步流为处理大量数据或需要流式处理数据的场景提供了一种高效且非阻塞性的方法,使得开发者能够更优雅地处理并发和数据流问题。
|
2月前
|
SQL 开发框架 .NET
EntityFramework数据持久化复习资料3、C#拓展方法与yield关键字使用
EntityFramework数据持久化复习资料3、C#拓展方法与yield关键字使用
34 0
|
2月前
|
存储 编译器 C#
|
9天前
|
开发框架 .NET 编译器
程序与技术分享:C#基础知识梳理系列三:C#类成员:常量、字段、属性
程序与技术分享:C#基础知识梳理系列三:C#类成员:常量、字段、属性
|
2月前
|
存储 数据管理 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机本身的数据保存(CustomData)功能(C#)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机本身的数据保存(CustomData)功能(C#)
39 0
|
2月前
|
SQL 存储 开发框架
C# DataSet结合FlyTreeView显示树状模型数据
C# DataSet结合FlyTreeView显示树状模型数据