C# – class, filed, property, const, readonly, get, set, init, required 使用基础
前言
心血来潮,这篇讲点基础的东西。
Field
比起 Property,Field 很不起眼,你若问 JavaScript,它甚至都没有 Field。
但在 C#,class 里头真正装 value 的其实是 Field,Property 只是 Filed 的读写器而已。
Field 长这样
public class Person
{
public int Age;
}
使用
var person = new Person();
Console.WriteLine(person.Age); // int default is 0
person.Age = 10; // set value
Console.WriteLine(person.Age); // get value: 10
const, readonly and init value
如果一个 Field 只能读,不能写,那我们可以用 const 去声明它。
public class Person
{
public const int Age = 5;
public const int Age2; // Error: A const field requires a value to be provided
} var person = new Person();
person.Age = 10; // Error : A readonly field cannot be assigned
const 的 init value 是写在 Filed 的结尾,一定要写 init value 哦,不然会报错。
readonly 也是用来声明只读 Field,它和 const 的不同在于,它比较宽松,在 constructor 阶段也允许 set init value。
public class Person
{
public readonly int Age = 1;
public readonly int Age2; // no error
public Person()
{
Age2 = 2; // if here no set init value Age2 will error.
}
}
如果两个都 set,construtor 会 override 掉 field assign。
注:下面这个写法是不 ok 的,它已经不算是 constructor 阶段的 set init value 了。
var person = new Person
{
Age = 15 // Error: A readonly field cannot be assigned
};
Field 的日常(Dependancy Injection)
平时很少会使用 Field 的,绝大部分情况我们用 Property,除了 Dependancy Injection。
public class HomeModel : PageModel
{
private readonly ILogger _logger; public HomeModel(ILogger<HomeModel> logger)
{
_logger = logger;
} public void OnGet()
{
_logger.LogInformation("Hello World");
}
}
一个 readonly Field,通过 construtor set init value,然后使用。
C# 12.0 primary construtor 的写法
public class HomeModel(ILogger<HomeModel> logger) : PageModel
{
public void OnGet()
{
logger.LogInformation("Hello World");
}
}
primary construtor 的 parameter 会被 compile 成 private Field,所以上面的代码和上一 part 的代码基本上是一样的。
唯一的不同是 primary construtor 目前无法声明 readonly Field。所以如果我们要 readonly 那就得多加一行。
public class HomeModel(ILogger<HomeModel> logger) : PageModel
{
private readonly ILogger _logger = logger;
public void OnGet()
{
_logger.LogInformation("Hello World");
logger.LogInformation("Hello World"); // 注意:logger 依然是可用的,因为它就是一个 Field 啊
}
}
Property
Property 是 Filed 的读写器,它长这样。
public class Person()
{
private int _age;
public int Age
{
get { return _age; }
set { _age = value; }
}
}
Filed 负责保存 value,Property 负责拦截读写过程。
这个是完整的写法,但日常生活中,大部分情况我们会用语法糖。
Auto Property
public class Person()
{
public int Age { get; set; }
}
Auto Property 是一种语法糖写法,前面是 Field,后面配上一个 { get; set; } 表达。它 compile 后长这样。

compiler 会替我们拆开它们。最终任然是一个 Field、一个 get 方法、一个 set 方法。
readonly = no set
public class Person()
{
public int Age { get; }
}
把 set 去掉就相等于 readonly Filed。注:没有 readonly Property 的,只有 no set。
set init value 的规则和 Field 一样。
public class Person
{
public int Age { get; } = 1;
public Person()
{
Age = 2;
}
} var person = new Person
{
Age = 3 // Error: Property or indexer 'Person.Age' cannot be assigned to -- it is read only
}
init keyword
上面例子中,实例化 Person 时,赋值是会报错的。这个是 readonly Field 的规则,我们只可以通过 construtor parameter 去实现 init 赋值。
这样局限太大了,于是 C# 6.0 推出了 init keyword。
public int Age { get; init; } = 1;
var person = new Person
{
Age = 3 // no more error
};
把 set 换成 init,它相等于 readonly 但是又允许实例化时赋值。
小总结:
有 3 个层次 assign value:field assign -> constructor assign -> new assign
它们分别对应 keyword:const -> readonly / no set -> init
required keyword
public class Person
{
public string Name { get; } // Warning Non-nullable property 'Name' must contain a non-null value
}
这是一个 readonly Property,它有一个 warning,因为我没有声明 init value。
public class Person
{
public string Name { get; } = "init value";
public Person()
{
Name = "init value";
}
}
我可以通过 2 种方式去设置 init value。这样就不会有 warning 了。
但是...如果它是 init keyword 呢?
public class Person
{
public string Name { get; init; } // Warning: Non-nullable property 'Name' must contain a non-null value
}
init 允许我们在实例化时才给予 init value,也就是说 class 内是可以不需要声明 init value 的。
但这导致它又 Warning 了。为了解决这个问题,C# 11 推出了 required keyword。
public class Person
{
public required string Name { get; init; }
}
声明 required keyword 后,它就不会 Warning 了。与此同时
var person = new Person(); // Error: Required member 'Person.Name' must be set
如果在实例化时忘记给予 init value,它还会报错提醒我们哦。
泛型限制也会报错哦
public class PersonOptions
{
public required string Name { get; set; }
} public class Person<T> where T : new() // 泛型限制 T 必须允许无参数实例化
{
} var person = new Person<PersonOptions>(); // Error : 'PersonOptions' cannot satisfy the 'new()' constraint
Best Practice
不限制模式
public class Person
{
public string Name { get; set; } = "";
public List<string> Values { get; set; } = [];
public Person Child { get; set; } = null!;
}
这个是最常见的定义,不做限制的好处是定义的时候省脑力,但对使用者来说就需要自己顾好好。
限制模式
public record class Person
{
public required string Name { get; init; }
public required List<string> Values { get; init; }
public required Person Child { get; init; }
}
record + required + init 可以很大的限制对象的读写。
对使用者来说是好事,不会忘记赋值,也不会不小心修改到值。
总结
这篇介绍了 class, filed, property, const, readonly, get, set, init, required 的基本使用方式。
它之所以有点混乱,主要是因为 C# 是经过了许多版本才一点一点逐步推出这些特性的。
这些特性和 private, protected, public 类似,都是用于限制 class 的使用者,如果使用者乖乖的话,其实我们大可不必去写这些限制。
C# – class, filed, property, const, readonly, get, set, init, required 使用基础的更多相关文章
- Swift - Property ''not initialized at super.init call
Property ''not initialized at super.init call 这个错误应该挺常见的的,为什么在百度上没有找到呢,stack over flow找到了,也不能说是什么解决办 ...
- org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'null' to required type 'double' for property 'band'; nested exception is org.springframework.core.convert.Con
本文为博主原创,未经允许不得转载: 先将异常粘贴出来: 20:37:26,909 ERROR [com.suning.fucdn.controller.ProductDataStaticsContro ...
- C# const, readonly, static readonly
转: Const 定义的是静态常在对象初始化的时候赋值.以后不能改变它的值.属于编译时常量.不能用new初始化. Readonly 是只读变量.属于运行时变量.可以在类constructor里改变它的 ...
- const,readonly 这些你真的懂吗? 也许会被面试到哦。。。
首先不可否认,这些在面试上会经常被面试官问起,但是你回答的让面试官满意吗?当然如果你知道了这些原理,或许你就不 怕了.既然说到了原理,我们还是从MSDN说起. 一:值得推敲的几个地方 1.先来看看ms ...
- static const readonly
C#中的static 和Java中的static 简单,两者用法完全是一致的.从两方面讨论: 1. 变量是属于类的,不是实例级别的.只能通过类名调用,不能通过实例调用. 2. 如果在定义时就赋值了,那 ...
- 如何使用C#关键字const,readonly,static
如果有一个值不太会变化,我们经常使用const和readonly,这2者有何不同呢?有时候,我们也会在readonly之前加上关键字static,这又意味着什么呢? const ● const默认是静 ...
- 二道Const,readonly 和 override, new的面试题
1. Const 和 readonly ; ; ; ; static void Main(string[] args) { Console.WriteLine("aa:{0},bb:{1}, ...
- Java的Final和C#的Const,Readonly比较分析(转载)
Java里面没有readonly关键字,预留了const的关键字,目前还没有实际用途,在Java中,跟这两个关键字比较接近的是final; C#中,两者都存在并可用.两者修饰的全局变量或局部变量都不能 ...
- C#面向对象几组关键字的详解(this,base,dynamic,var,const,readonly,is,as)
× 目录 [1]this和base的区别 [2]var和dynamic的区别 [3]const和readonly的区别 [4]is和as的区别 这几个关键字,在用法上有许多相似之处.这里主要看看细节之 ...
- const readonly
静态常量(compile-time constants)静态常量是指编译器在编译时候会对常量进行解析,并将常量的值替换成初始化的那个值. 动态常量(runtime constants)而动态常量的值则 ...
随机推荐
- 2024-07-13:用go语言,给定一个从0开始的长度为n的整数数组nums和一个从0开始的长度为m的整数数组pattern,其中pattern数组仅包含整数-1、0和1。 一个子数组nums[i.
2024-07-13:用go语言,给定一个从0开始的长度为n的整数数组nums和一个从0开始的长度为m的整数数组pattern,其中pattern数组仅包含整数-1.0和1. 一个子数组nums[i. ...
- 如何支持同一台电脑上使用不同版本的Node.js版本
在我们实际项目开发过程中,经常不同项目使用的node.js版本会也有所不同,为了方便维护不同版本的项目.可以使用nvm来解决. 1.下载nvm https://github.com/coreybutl ...
- 直播预告:Service Mesh 技术在美团的落地和挑战
一场突如其来的疫情加深了企业对数字化转型升级的渴望,作为新兴数字化业务的基础,云原生技术的价值日益凸显.当前,越来越多的企业逐步引入容器.微服务/Service Mesh 技术改造业务,实现数据库.P ...
- RSA加解密,Java和C#互通
一.使用场景 Java作为服务端生成一对公私钥,C#作为客户端拥有公钥. RSA算法这里就不多做介绍了,可参考RSA算法介绍 二.规范 公私钥的形式都是base64字符串 通过公私钥加密后的字符串也是 ...
- 题解:P7482 不条理狂诗曲
题解:P7482 不条理狂诗曲 本题解借鉴 blossom_j 大佬思路,但这位大佬的题解似乎没放正确代码. 题意 对于每一个 \(a\) 的子区间 \(a_{l\dots r}\),求选择若干个不连 ...
- OpenAI深夜丢炸弹硬杠谷歌搜索
这几年科技变革太快,AI更是飞速发展,作为一名IT老兵,使用过的搜索引擎也是一换再换.这不,刚消停了一段时间的OpenAI又丢出一个炸弹SearchGPT,直接跟谷歌掀桌子了. 1.谷歌搜索的无奈 早 ...
- FFmpeg开发笔记(四十一)结合OBS与MediaMTX实现SRT直播推流
<FFmpeg开发实战:从零基础到短视频上线>一书的"10.2 FFmpeg推流和拉流"提到直播行业存在RTSP和RTMP两种常见的流媒体协议.除此以外,还有于20 ...
- 错误记录java: JDK isn't specified for module
跑苍穹外卖的时候遇到了 java: JDK isn't specified for module 'sky-pojo'这一问题 解决办法是通过修改JDK版本,这个项目用的springboot比较早,可 ...
- 6、SpringMVC之视图
注意:本文环境搭建请参考5.2节 6.1.视图概述 视图的作用是渲染数据,将模型Model中的数据展示给用户: SpringMVC视图的种类很多,默认有转发视图和重定向视图: SpringMVC中的视 ...
- 【Docker】08 部署挂载本地目录的MySQL
拉取MySQL镜像: docker pull mysql:8.0.21 执行挂载运行MySQL容器的命令: docker run -dit \ --name mysql-test \ -p 3306: ...