C# 字段(Field)与属性(Property)的区别

  • 字段和属性,都是成员变量,都用于存取数据。
  • 字段读写无限制,属性通过get和set方法可以控制读写(比如可以在年龄Age属性的set方法中限制,当赋值的value大于200时,则赋值默认值100,从而确保数据准确性)。
  • 按照类的设计原则,字段一般用在类的内部使用(private),属性一般供外部类访问(public)。

示例类

cs 复制代码
public class TestClass
{
    //私有字段
    private string privateField;
    //公有字段(实际开发时,存在公有的字段)
    public string publicField;
    //静态字段
    public static string staticField;
    //私有属性
    private string privateProp { get; set; }
    //公有属性
    public string publicProp { get; set; }
    //静态属性
    public static string staticProp { get; set; }

    //重写ToString方法
    public override string ToString()
    {
        return $"privateField:{privateField},publicField:{publicField},staticField:{staticField},privateProp:{privateProp},publicProp:{publicProp},staticProp:{staticProp}";
    }
}

使用System.Reflection反射验证

cs 复制代码
public string GetName()
{
    string infoStr = string.Join(",", typeof(TestClass).GetFields().Select(s => s.Name));
    string propStr = string.Join(",", typeof(TestClass).GetProperties().Select(s => s.Name));
    return $"{infoStr}  ||  {propStr}";
}
// 等价于
public string GetName()
{
    //BindingFlags绑定Public(公有)、Instance(实例)、Static(静态)
    string infoStr = string.Join(",", 
        typeof(TestClass).GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
        .Select(s => s.Name));
    string propStr = string.Join(",", 
        typeof(TestClass).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
        .Select(s => s.Name));
    return $"{infoStr}  ||  {propStr}";
}

结果为:publicField,staticField || publicProp,staticProp

使用System.Reflection的GetFields获取类的字段信息,使用GetProperties获取类的属性信息,默认获取Public(公有)、Instance(实例)、Static(静态)的变量

加上BindingFlags.NonPublic条件获取会得到以下结果

cs 复制代码
string infoStr = string.Join(",", 
                typeof(TestClass).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)
                .Select(s => s.Name));
string propStr = string.Join(",", 
                typeof(TestClass).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)
                .Select(s => s.Name));

infoStr为:privateField,publicField,<privateProp>k__BackingField,<publicProp>k__BackingField,staticField,<staticProp>k__BackingField

propStr为:privateProp,publicProp,staticProp

propStr的值是预期之内的,多加了BindingFlags.NonPublic条件,就多获取到私有的privateProp属性。

infoStr的值却意料之外,除了多了privateField私有字段,还多了几个名字带有属性名的k__BackingField字段。

在C#中,k__BackingField是一个常见的编译器生成的字段名称,它用于实现属性的自动属性(auto-implemented properties)。

在C#中,自动属性允许你声明一个属性而不显式定义后备字段。编译器会自动为你创建一个私有的后备字段,并为你提供getter和setter的默认实现。这个自动创建的后备字段的名称通常以k__BackingField结尾。

例如,考虑以下代码:

cs 复制代码
public class MyClass
{
    public int MyProperty { get; set; }
}

编译器实际上会为你生成如下的代码:

cs 复制代码
public class MyClass
{
    private int <MyProperty>k__BackingField;

    public int MyProperty
    {
        get
        {
            return <MyProperty>k__BackingField;
        }
        set
        {
            <MyProperty>k__BackingField = value;
        }
    }
}

注意,<MyProperty>k__BackingField是编译器生成的字段名称。在实际代码中,你不应该直接访问这个字段,因为它是一个实现细节,可能会在不同的编译器版本或不同的编译器设置下发生变化。

相关推荐
唐青枫11 小时前
别把日志、权限写进业务方法:C#.NET 动态代理从原理到实战
c#·.net
fujisheng66112 小时前
Unity UI 生命周期状态机:处理 Covered、异步竞态与事务回滚
c#·unity3d
leoZ23117 小时前
第 8 篇:与 AI 协作的工作流 + 完整案例
前端·人工智能·神经网络·自然语言处理·性能优化·c#·php
fujisheng66119 小时前
Unity 异步 UI 实战:取消令牌、版本校验与旧句柄隔离
c#·unity3d
额鹅恶饿呃20 小时前
随着CentOS官方停服的时间越来越久,大量仍在使用CentOS7的企业和运维从业者
java·python·算法·c#·ruby
乌药ice20 小时前
c#中一个多线程安全的HashSet
开发语言·c#
lfSeanDragon20 小时前
数据结构-前缀树(Trie)
开发语言·c#
张人玉21 小时前
基于 C# WinForms + .NET 8 + SQLite + TCP Socket 的多连接通讯调试工具——TCP通讯助手(TcpAssistant)
tcp/ip·sqlite·c#·.net
mldong1 天前
C# 开发者也有自己的轻量工作流引擎了:NuGet 装包,5 分钟跑通一条审批流
后端·c#·.net
samble1 天前
从零搭建工业控制系统(二十二):线程安全与并发控制
c#·wpf·并发·mvvm·线程安全·工业控制