【橙子老哥】c# 探究属性与字段本质

hello,大家好,叕到了橙子老哥的分享时间,希望大家一起学习,一起进步。

首先祝大家国庆快乐~

其次,欢迎加入.net意社区,第一时间了解我们的动态,地址:ccnetcore.com

今天,我们来个简单的,来点关于属性与字段有趣的骚操作,废话少说,我们直接开始

1、本质

属性是什么,字段是什么,这里不在这篇文章赘述了,我来直接探究下它的原理

上代码,不解释
我们写一个类,其中包含一个私有属性,一个公开属性

class MyClass
{
    private string UserName { get; set;}
    public string Name { get; set; }

    public void Log()
    {
        Console.WriteLine(UserName);
    }
}

想要知道它到底做了什么,IL一看究竟

[NullableContext(1)]
[Nullable(0)]
internal class MyClass
{
  [CompilerGenerated]
  [DebuggerBrowsable(DebuggerBrowsableState.Never)]
  private string <UserName>k__BackingField;
  [CompilerGenerated]
  [DebuggerBrowsable(DebuggerBrowsableState.Never)]
  private string <Name>k__BackingField;

  private string UserName
  {
    [CompilerGenerated] get
    {
      return this.<UserName>k__BackingField;
    }
    [CompilerGenerated] set
    {
      this.<UserName>k__BackingField = value;
    }
  }

  public string Name
  {
    [CompilerGenerated] get
    {
      return this.<Name>k__BackingField;
    }
    [CompilerGenerated] set
    {
      this.<Name>k__BackingField = value;
    }
  }

  public void Log()
  {
    Console.WriteLine(this.UserName);
  }

  public MyClass()
  {
    base..ctor();
  }
}

可以看到无论属性是公开还是私有,都会新增一个字段

private string <UserName>k__BackingField;
private string <Name>k__BackingField;
而对应的set、get方法,就有私有及公开区分

  private string UserName
  {
    get
    {
      return this.<UserName>k__BackingField;
    }
    set
    {
      this.<UserName>k__BackingField = value;
    }
  }
 public string Name
  {
    get
    {
      return this.<Name>k__BackingField;
    }
    set
    {
      this.<Name>k__BackingField = value;
    }
  }

这里的get、set,本质上就是一个方法的语法糖,会编译成对应的get方法和set方法,如果熟悉java的人,对这个印象肯定深刻

看到这里,其实答案也就写在脸上了,c# 中的属性,本质上是使用get、set方法,包了一层私有字段。私有字段会叫一个特殊名字<xxxx>k__BackingField,低级别的c#语法是允许命名加特殊字符的,就是防止重名,因为你不能取这样的名称

2、进阶

既然清楚了属性和字段的本质,我们再来玩一下它的一些骚操作

我们可以给私有属性赋值吗?当然可以

对象的操作,C#没有什么是做不到的

例如上方代码中,我们定义的私有的UserName属性,我们实操一下,把这个私有属性赋值

var my=new MyClass(){Name = "张三"};
var property =typeof(MyClass).GetProperty("UserName",BindingFlags.NonPublic | BindingFlags.Instance);
property.SetValue(my,"私有属性");
my.Log();

最终输出:私有属性,赋值成功

这个操作也很简单,需要注意的是,在条件中,需要指明BindingFlags.NonPublic | BindingFlags.Instance,否则也是查不出来的,因为默认的方法有一层过滤:

    public PropertyInfo? GetProperty(string name)
    {
      return this.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
    }

另外,属性本质是给一个私有字段包一层,那我们理论上不是可以直接操作字段?当然可以

针对我们上面研究的本质,属性生成的字段叫做:<xxx>k__BackingField,那我们就去找这个字段,并给它赋值

var my=new MyClass(){Name = "张三"};
var property =typeof(MyClass).GetProperty("UserName",BindingFlags.NonPublic | BindingFlags.Instance);

var field =typeof(MyClass).GetField("<UserName>k__BackingField",BindingFlags.NonPublic | BindingFlags.Instance);


property.SetValue(my,"私有属性");
my.Log();
field.SetValue(my,"私有字段");
my.Log();

输出:私有属性 私有字段 属性和字段都修改成功

Nice,是不是很有意思?属性和字段还不直接拿捏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值