C#中字段、属性和构造函数赋值的问题

提出问题

首先提出几个问题:

1、如何实现自己的注入框架?

2、字段和自动属性的区别是什么?

3、字段和自动属性声明时的直接赋值和构造函数赋值有什么区别?

4、为什么只读字段和只读自动属性(只有get没有set访问器)都可以在构造函数中进行赋值?

5、反射可以给只读字段或者只读属性进行赋值吗?

6、自动属性和普通属性的区别?

这些问题是我在试着写自己的注入实现时遇到的问题。这些问题应该在学习C#时的第一节课就应该学到了,我看网上还有人分享说他在面试时遇到面试官问为什么只读字段和只读自动属性可以在构造函数中进行赋值,他没有回答上来,然后他写文章探讨这个问题,却没有得出一个明显的答案,实在可惜。网上关于只读属性有些是写ReadOnly特性的,读到这些文章直接跳过吧,老版本的C#现在看也没什么帮助。

给出答案

2、属性比字段多了get/set访问器;字段是在内存中声明的一个内存空间,可以实实在在的存储值;属性像字段一样使用,却可以有自己的代码段,能赋值取值,是因为访问属性就是调用属性的get/set方法对字段进行取值赋值(或者不操作字段);在MSDN上,建议字段作为类的私有变量使用private/protected修饰,属性则往往作为共有属性使用public修饰;字段的读取和操作都是直接操作内存,属性是调用get/set访问器,所以字段比属性快。

3、准确来说,没有区别。区别仅仅是直接赋值先执行,构造函数赋值后执行。在生成的IL中间语言(C#代码先编译成IL代码,然后才编译成汇编语言)中,字段直接赋值和构造函数赋值是在同一个代码段中(构造函数中)的。

4、这个问题可以和上面的问题联合起来回答。构造函数作为实例化一个类的入口,是最先访问的。字段的直接赋值其实也是放在构造函数中执行的,所以才说直接赋值和构造函数赋值没有区别。“只读”的限制只是由C#编译器(CLR)维护的,我觉得全名应该叫做“除构造函数外只读”更加准确,这是C#语法的规则记住就行(这是当然,直接赋值其实是放在构造函数中进行赋值的,如果构造函数不能赋值那只读字段没有值和没有声明一样);

5、这个问题又可以和上面的问题联系起来一起回答。通过反射可以给自读字段赋值但是无法给只读属性进行赋值(不相信的可以试一下)。对只读字段的赋值是因为绕过了C#编译器(CLR)的只读显示,对只读属性赋值的话是还是调用set访问器对字段进行赋值,因为没有set访问器所以允许后会报错。那么问题来了,那为什么只读自动属性没有set访问器还可以在构造函数中赋值呢?其实只读自动属性在构造函数中进行赋值,实质上是对字段进行赋值,和属性的get/set访问器没有关系。

6、区别是什么?上面一直强调自动属性,是因为自动属性和普通属性不一样,比如只读普通属性(没有set访问器)无法在构造函数中赋值。在没有自动属性之前,普通属性使用步骤是首先声明一个字段如_id,然后声明一个属性Id,在get和set访问器中做一些操作,这些操作大多数是对字段_id的操作,但是有时候和字段没有关系。普通属性可以像字段一样通过“.”的方式调用,但又像方法一样具有代码段(普通属性从来不开辟内存空间)。

但是C#3.0之后引入了自动属性,声明方式如public int id { get; set; },C#6.0之后又有了public string FirstName { get; set; } = "Jane"。自动属性肯定开辟了内存空间然后才有了自动属性的直接赋值。其实在类中声明自动属性会在编译成IL中间语言中声明一个隐藏字段,然后生成隐藏字段的get/set方法,然后生成get/set访问器。这里可以解释为什么只读普通属性无法在构造函数中赋值(和直接赋值)而只读自动属性可以在构造函数中赋值(和直接赋值),因为不论直接赋值还是在构造函数中赋值,生成的IL代码中的构造函数中,操作的都是隐藏字段,并没有访问属性的set访问器。(注意这里只是说的类中的自动属性,接口中也是可以有自动属性的,但是接口的自动属性并不会生成隐藏字段只是定义get/set访问器)

开始解释

通过C#生成的IL中间语言代码可以知道的更清楚

可以看到,自动属性会生成一个名称为 '<age>k__BackingField' 的隐藏私有字段+私有字段的get/set方法+属性代码段;

可以看到IL代码生成了User的构造函数 .ctor,ctor是构造函数(Constructor)。

不论直接赋值还是构造函数赋值,都是在.ctor中执行的,并且操作的都是字段,自动属性的赋值操作的是隐藏字段。

  public interface IUser{    int id { get; set; }}

可以看到,接口中的自动属性并没有生成隐藏字段。

其他说明

1、上文中提到“反射可以给只读字段进行赋值但是无法给只读属性进行赋值”。无法给只读属性进行赋值是因为没有set访问器。但是我们已经知道了可以给字段赋值,并且只读属性会生成隐藏字段,那我们是不是可以通过给隐藏字段进行赋值间接达到给自动属性赋值的目的呢?答案是可以的!

定义User的只读自动属性

控制台的反射赋值代码:

运行

2、因为隐藏字段是私有的,所以取到隐藏字段需要  BindingFlags.NonPublic

3、只读自动属性说明不想被访问到那为什么还要给它赋值呢?这个问题……做着玩,项目中我觉得也没有什么用到的机会……

原文地址:https://www.cnblogs.com/gdpw/p/9463145.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

C#中字段、属性、只读、构造函数赋值、反射赋值的相关相关推荐

  1. python中choice的用法_Django模型中字段属性choice使用说明

    今天设计models时,用到了choice这个属性,用来限制用户做出选择的范围.比如说性别的选择(男或女). class User(AbstractUser): ... sex = models.Ch ...

  2. MySQL中字段属性——枚举类型(ENUM)

    在MySQL中,对于"省份" ,"民族","性别"等会存在大量重复字段值并且可以预定义为一个不重复的字符串集合的字段,就可以定义为枚举类型. ...

  3. pgsql修改表中字段属性

    语句 ALTER table 表名 ALTER COLUMN 字段名 type 修改类型 USING 表名::double precision 示例 ALTER table t_menu ALTER ...

  4. 回复:lerit的关于对象中字段的初始化问题

    谢谢lerit的对于我的博文<内存探寻1之--值类型和引用类型的内存分配机制>中提到的问题.这里先重述问题: "你好,你的文章写得很好,清晰了很多以前比较模糊的概念,我想提个问题 ...

  5. oracle,mysql常用基本操作 字段属性

    1.Oracle 1.向数据表添加注释及查询表注释 SELECT * FROM USER_TAB_COMMENTS WHERE TABLE_NAME='表名'; --查询注释 COMMENT ONTA ...

  6. [译]JavaScript中的属性:定义和赋值的区别

    原文:http://www.2ality.com/2012/08/property-definition-assignment.html 你知道吗?定义一个属性和为一个属性赋值是有区别的.本文解释了两 ...

  7. C#中使用属性及get,set访问private字段和直接用public修饰字段的对比和理解

    导语 本篇仅作为初学C#的随笔,内容较基础,适合初级水平开发者,浅谈主题中的话题,从两者的相同点,不同点,和如何选三个角度探讨,希望文章能起到抛砖引玉的作用,欢迎补充和纠正. 如果你并不想花费十分钟左 ...

  8. Java反射之Filed(类中的属性对象)

    通过反射机制获取类中的属性对象. 1.获取类中所有的public属性(包括父类):getFields(): public class TestFiled {class A{public int age ...

  9. Dynamics CRM: 表单(Form)中的显示字段变成只读的几种情况

    有的时候,当我们打开一条记录, 我们会发现这条记录或者记录中的某个字段变成了不可编辑的状态, 但让表单中的显示字段变成只读的情况有很多, 你可以使用JS代码中的setDisabled, 也可以使用系统 ...

最新文章

  1. linux文件描述符
  2. 掘金小册Jenkins大纲准备
  3. 苹果手机透明桌面_苹果官网上,一个透明手机壳卖300多块钱,是不是在耍我们?...
  4. TensorFlow 自动文本摘要生成模型,2016
  5. ArrayList 和 LinkedList 的自定义实现
  6. MySQL5.6 选项和变量整理
  7. CNI:容器网络接口详解
  8. 双机热备_什么是高可用双机热备?双机热备概念原理详解
  9. 【python】列表的定义与操作
  10. pytorch提取softmax前的特征并保存为txt文件
  11. c语言基础--ASCII码表
  12. 最简单的省市区三级联动
  13. Google如何对图片搜索结果进行排名
  14. 蓝桥网算法提高 学霸的迷宫
  15. 英科学家用扫描技术成功读取大脑记忆
  16. 输入你的密码来连接到_查看电脑已连接的WIFI密码
  17. Openwrt-USB网络共享
  18. 如何命名计算机快捷键,重命名的快捷键,教您重命名的快捷键是什么
  19. GitChat·技术管理 | Cynefin 框架和不确定性管理思维
  20. 第6章第23节:文字视觉化:使用图片来诠释文字的涵义 [PowerPoint精美幻灯片实战教程]

热门文章

  1. javascript基础修炼(4)——UMD规范的代码推演
  2. 利用系统错误日志监控磁盘健康状况
  3. WCF分布式开发常见错误(25):The certificate 'CN=WCFHTTPS' must have a private key
  4. hadoop扩充磁盘操作记录
  5. 安装配置libmemcached
  6. 在SQLSERVER企业管理器中如何创建触发器
  7. WSUS专题之二:部署与规划1
  8. 一行代码完成定时任务调度,基于Quartz的UI可视化操作组件 GZY.Quartz.MUI
  9. 太神奇了!使用C#实现自动核验健康码:(2)OCR识别
  10. NET问答: 为什么仅有 getter 的属性,还可以在构造函数中赋值 ?