@C#8.0 and .NET Core 3.0 高级编程学习笔记
为了能精细地完成对C#语言的学习,我决定选择一本书,精读它,理解它,记录它。我想选择什么书并不是最重要的,最重要的是持之以恒的完成这本书的学习实践,并最终转化成自己的能力。
《C#8.0和.NET Core 3.0高级编程》 [英]马克.J.普莱斯 著 王莉莉 译 ,写出来书名主要是为了方便其他看到我这篇文章的读者参照,无任何其他目的。
以此书为蓝本,我预计对1-13进行重点学习。对于 C#的实际应用由于场景太多,我只选择对于我工作学习有用的章节进行学习记录。
大多数人学习复杂主题的最佳方式是模仿和重复,而不是阅读关于理论的详细解释
3种代码编辑器
1、Visual Studio Code
2、Visual Studio 2019
3、Visual Studio 2019 for Mac
实现跨平台编程(Linux Windows Mac)
创建windows应用程序的唯一编辑器,当然它也可以创建linux应用程序
主要用创建在IOS等苹果操作系统设备上的应用程序
章节 | 工具 | 操作系统 |
---|---|---|
第1-19章 | Visual Studio Code | Windows macOS Linux |
第20章 | Visual Studio 2019 | Windows 10 |
第21章 | Visual Studio 2019 for Mac | macOS |
.NET Core 3.0支持跨平台部署 Linux Windows Mac
微软几乎每隔几个月就会发布Visual Studio Code新特性版本以修复版本bug
常见键盘快捷键
动作 | macOS | Windows |
---|---|---|
show command palette | cmd+shift+p 和F1 | Ctrl+Shift+P 和F1 |
Go to Definition | F12 | F12 |
建议根据自己的操作系统下载pdf操作系统快捷键
软件名称 | 下载链接 | 说明 |
---|---|---|
visual studio code | download | 建议使用稳定版本 |
NET Core SDK | download | - |
C#扩展 | - | - |
扩展 | 说明 |
---|---|
c# for visual studio code | 提供c#编辑支持,包括语法高亮,智能感知 |
c# xml documentation comments | 为visual studio code 生成xml文档注释 |
c# extensions | 添加c#类 接口 |
REST Client | 发送HTTP请求并在visual studio code 中直接查看响应 |
.NET Framework .NET Core Xamarin 和.NET Standard是相关的,他们是开发人员用来构建应用程序和服务平台
.NET Framework开发平台包括公共语言运行库(CLR)和基础类库(BCL),前者负责管理代码的执行,后者提供了丰富的类库来构建应用程序
实际上,.NET Framework仅适用于windows
一些第三方开发了名为Mono项目的.NET Framework实现,Mono是跨平台的。其作为Xamarin移动平台及Unity等跨平台游戏开发平台的基础,找到了自己的应用价值
为了解决跨平台问题,微软退出.NET Core平台
2020年11月 .NET Core 简化为.NET
.NET Core 不同版本
版本 | 发布日期 |
---|---|
.NET Core 1.0 | 2016年6月 |
.NET Core 2.0 | 2017年8月 |
.NET Core 3.0 | 2019年9月 |
.NET 5.0 | 2020年11月 |
.NET 6.0 | 2021年11月 |
LTS版本是稳定的,在其生命周期中少有更新
相比.NET Framework 的当前版本要小,是因为旧技术已经被移除;
微软的目的不是让.NET Core 变小,而是将其组建化,部署时按需选择即可
微软定义了所有.NET平台都必须实现的API规范 .NET Standard;
理解.NET Standard只是一种标准很重要,.NET Standard版本以及支持这些版本的.NET平台download
visual studio code
dotnet CLI工具使用的C#编译器(Roslyn)会将C#源代码转换成中间语言(Intermediate Language,IL)代码,并将IL存储在程序集(DLL或exe文件)中,IL代码语句就像汇编语言指令,由.NET Core的虚拟机CoreCLR执行
.NET Native用于将C#代码提前(Ahead of Time ,AoT)编译成本机CPU指令,而不是用CLR编程成IL代码。故执行速度快,占用内存低
.NET技术 | 说明 | 驻留的操作系统 |
---|---|---|
.NET Core | 现代功能集 完全支持C#8.0 | 跨平台 |
.NET Framework | 旧的特性集 | windows |
Xamarin | 移动及桌面应用 | Android ios macos |
微软承诺将来只有一个.NET平台而不是3个 |
github上pull push 代码速度很慢,推荐使用gittee代替(码云)
权威资源download
dotnet help new
Go to Definition (快捷键F12)
Stack Overflow 是最受欢迎的第三方网站。 虽然作者这么说,但是国内访问速度比较慢
使用goggle浏览器搜索答案比较准确
.NET 官方博客地址
1.0==》8.0特性简介
版本 | 特性说明 |
---|---|
1.0 | 2002年发布,包含静态类型的面向对象编程语言 |
2.0 | 2005年发布,泛型实现强数据类型,以提高代码性能,减少类型错误 |
3.0 | 2007年发布,集成查询LINQ,匿名类型,lambda表达式等 |
4.0 | 2010年发布,F#,Python等动态语言改进互操作性 |
5.0 | 2012年发布,简化异步操作支持 |
6.0 | 2015年发布,细微改进 |
7.0 | 2017年发布,添加功能语言特性 |
7.1 | 2017年8月发布,对语言细微改进 |
7.2 | 2017年12月发布,对语言细微改进 |
7.3 | 2018年发布,关注性能导向型安全代码,改进了ref变量,指针,stackalloc |
8.0 | 2019年发布,关注空处理处理 |
C#7.x中,微软加快了语言发布节奏–发布次要版本号,也称为点发布
.NET语言编译器 作为.NET Core SDK的一部分发布
在vscode中查看由哪些可以使用的版本
dotnet --version
在项目文件中添加配置元素
8.1
*注释永远不应该是记录代码的唯一方式,为变量和函数选择合理的名称,编写单元测试和创建文字文档是记录代码的其他方法
C#词汇表是由关键字,符号字符和类型组成
大约100个关键字 using namespace class…
//loop through the assamblies that this app reference
foreach (var r in Assembly.GetEntryAssembly().GetReferencedAssemblies())
{
//load the assembly so we can read its details
var a=Assembly.Load(new AssemblyName(r.FullName));
//declare a variable to count the number of methods
int methodCount=0;
//loop through all the types in the assembly
foreach (var t in a.DefinedTypes)
{
// add up the counts of methods
methodCount+=t.GetMethods().Count();
}
// output the count of types and their methods
System.Console.WriteLine(
"{0:N0} types with {1:N0} methods in {2} assembly .",
arg0:a.DefinedTypes.Count(),
arg1:methodCount,
arg2:r.Name);
}
当使用变量时,首先考虑它可能在内存中的占用的空间,然后考虑处理速度
命名约定 | 示例 | 使用场合 |
---|---|---|
驼峰样式 | Cost orderDetail dateofBirth | 局部变量 私有字段 |
标题样式 | String Int32 Cost DateOfBirth Run | 类型 非私有字段以及其他成员(如方法) |
遵循一组一致的命名约定,可以使代码更容易被自己或者其他开发人员理解(更重要的是未来的自己) |
表示固定值的符号
char a='a';
char b='1';
string name="yong";
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(name);
string fullname="Tim\tSun";
Console.WriteLine(fullname);
//理解逐字字符串
string fileRoute=@"C:\test\sony\123.txt"
Console.WriteLine(fileRoute);
int count1=1_0000_0000;
int count2=1;
int count3=count1+count2;
Console.WriteLine(count3.ToString());
2. 存储实数
计算机并不能总是精确地表示浮点数 float和double类使用单精度和双精度浮点数存储实数
IEEE754是电气和电子工程师协会(IEEE)于1985年建立的浮点运算技术标准
3. 编写代码探索数字的大小
使用sizeof() MinValue MaxValue 观察类型占用空间的大小和最小最大值
//观察各种数字类型占用的空间及最大最小值
Console.WriteLine($"int uses {sizeof(int)} bytes and can store numbers in the range {int.MinValue:N0} to {int.MaxValue:N0}");
Console.WriteLine($"int uses {sizeof(float)} bytes and can store numbers in the range {float.MinValue:N0} to {float.MaxValue:N0}");
Console.WriteLine($"int uses {sizeof(double)} bytes and can store numbers in the range {double.MinValue:N0} to {double.MaxValue:N0}");
输出结果
4. 比较double和decimal类型
double类型不能保证值是准确的,因为有些数字不能表示为浮点值。
//CP02--比较double和decimal
double a=0.1;
double b=0.2;
double c=a+b;
if (c==0.3)
{
System.Console.WriteLine($"{a}+{b} equals 0.3 ");
}
else
{
System.Console.WriteLine($"{a}+{b} does not equals 0.3 ");
System.Console.WriteLine($"{a}+{b} equals {c}");
}
输出结果
永远不用用==比较2个double值。在第一次海湾战争,美国爱国者导弹系统计算时使用double值,这种不准确性导致其无法跟踪拦截伊拉克飞毛腿导弹
解决办法
System.Console.WriteLine("use decimal type to solute !!");
decimal d=0.1M;//M suffix means a decimal literal value
decimal e=0.2M;
decimal f=d+e;
if (f==0.3M)
{
System.Console.WriteLine($"{d}+{e} equals 0.3 ");
}
else
{
System.Console.WriteLine($"{d}+{e} does not equals 0.3 ");
System.Console.WriteLine($"{d}+{e} equals {f}");
}
输出结果(注意double和decimal类型无法直接==运算)
decimal类型是准确的,常用于货币,CAD绘图,一般工程学以及任何对实数的准确性要求较高的场合
true false
在使用工作区时,在终端输入命令一定要小心,保证当前处于你想要的文件路径中
@不知道为什么作者在这个部分说明这个问题?可能他在这里入过坑
object 可以存储任何数据,代价是代码混乱,性能较差
C#1.0版本就有了object类型,但是在C#2.0以后有更好的选择泛型。泛型可以提供想要的灵活性,且没有性能开销。见第6章
dynamic 可用于存储任何类型的数据,灵活性比object更强。代价是性能降低了
并且他可以在没有显示强制转换的情况下调用成员
//dynamic 类型
dynamic anothername="tom";
int length=anothername.Length;
System.Console.WriteLine($"its length is {length}");
制定或推断变量类型
//声明变量 指定或推断变量的类型
System.Console.WriteLine("declear or just use keyword var");
var count=3; //clearly enough
var height=1.2;
var price=4.9M;
var file1=File.CreateText(@"something1.txt"); //must take some time to think
StreamWriter file2=File.CreateText(@"something2.txt"); //more clearly
除了string之外,其他基本类型都是值类型,意味着他们必须有值。可以使用default()操作确认
而string是引用类型,可以有空值
System.Console.WriteLine("");
// 获取类型默认值
System.Console.WriteLine("获取类型的默认值");
System.Console.WriteLine($"default(int) is {default(int)}");
System.Console.WriteLine($"default(bool) is {default(bool)}");
System.Console.WriteLine($"default(DateTime) is {default(DateTime)}");
System.Console.WriteLine($"default(string) is {default(string)}");
需要存储同一类型的多个值,可以用数组
System.Console.WriteLine("认识数组");
string[] names=new string[3];
names[0]="tim";
names[1]="tom";
for (int i = 0; i < 3; i++)
{
System.Console.WriteLine($"name is {names[i]}");
}
默认情况下,想int DateTime这样的类型都有值,但有时,当读取存储在数据库中允许的空值或缺失值时,允许空值非常方便
System.Console.WriteLine("");//隔行
// 定义可空变量
System.Console.WriteLine("定义可空变量");
int? thiscanbenull=4;
thiscanbenull=null;
System.Console.WriteLine($"thiscanbenull is {thiscanbenull}");
<propertyGroup>
<Nullable>enable</Nullalbe>
</propertyGroup>
#nullable disable
#nullable enable
//使用编号的位置参数进行格式化
System.Console.WriteLine("使用编号的位置参数进行格式化");
int number=10;
decimal price11=1.2M;
System.Console.WriteLine(
format:"{0} apples costs {1:c}",
arg0:number,
arg1:number*price11);
int a=10;
System.Console.WriteLine($"{a} is 10")
N0格式表示有千位分隔符且没有小数点的数字 C格式表示货币 {arg,N} N=-8 左对齐8个字符长度列 {arg,N} N=6 右对齐6个字符长度列
//格式字符串例子
System.Console.WriteLine("格式字符串例子");
System.Console.WriteLine(
format:"{0,-8} {1,6:N0}",
arg0:"name",
arg1:"count");
System.Console.WriteLine(
format:"{0,-8} {1,6:N0}",
arg0:"apple",
arg1:123456);
System.Console.WriteLine("----获取用户文本输入-----");
System.Console.WriteLine("type your name and press enter ");
string name123=System.Console.ReadLine();
System.Console.WriteLine("type your age and press enter ");
string age=System.Console.ReadLine();
System.Console.WriteLine($"so your name is {name123} and your age is {age}");
using System
导入名称空间的效果是,名称空间的所有可用类型都对程序可用,不需要输入空间名称前缀
System.Console.WriteLine("----获取用户的重要输入-----");
System.Console.WriteLine("press any key combination");
ConsoleKeyInfo key=ReadKey();
WriteLine();
System.Console.WriteLine(
format:"key:{0},Char:{1},Modifiers:{2}",
arg0:key.Key,
arg1:key.KeyChar,
arg2:key.Modifiers);
Main方法中的string[] args是用于向控制台应用程序传递参数数组
命令行参数由空格分隔
System.Console.WriteLine("");
//获取参数
System.Console.WriteLine("---获取参数---");
System.Console.WriteLine($"main input args {args[0]}");
可以设置控制台的背景颜色,尺寸等参数
try catch
探索主题
主题 | 链接 |
---|---|
C#关键字 | 资料下载 |
++ –
//一元操作符
System.Console.WriteLine("----一元操作符----");
int a=3;
int b=a++;
System.Console.WriteLine($"b is {b}, a is {a}");
//逻辑运算符
System.Console.WriteLine("");
System.Console.WriteLine("---逻辑运算符---");
bool h = true;
bool i = false;
System.Console.WriteLine(
format: "{0,-8}\t{1,-8}\t{2,-8}",
arg0: "AND",
arg1: "h",
arg2: "i");
System.Console.WriteLine(
format: "{0,-8}\t{1,-8}\t{2,-8}",
arg0: "h",
arg1: $"{h & h}",
arg2: $"{h & i}");
System.Console.WriteLine(
format: "{0,-8}\t{1,-8}\t{2,-8}",
arg0: "i",
arg1: $"{i & h}",
arg2: $"{i & i}");
也称短路布尔运算符
//条件逻辑运算符
System.Console.WriteLine("");
System.Console.WriteLine("---条件逻辑运算符---");
System.Console.WriteLine($"h & DoStuff() = {h & DoStuff()}");
System.Console.WriteLine($"i & DoStuff() = {i & DoStuff()} ");
System.Console.WriteLine("---------");
System.Console.WriteLine($"h && DoStuff() = {h && DoStuff()}");
System.Console.WriteLine($"i && DoStuff() = {i && DoStuff()} ");
从示例中可以看出为什么条件逻辑运算符被描述未短路布尔运算符,它们可以使得应用程序更高效。但是会在假定函数总是被调用的情况下引入一些细微bug
二元移位运算符相比传统的运算符执行更快,因为它操作的是数字的位
位运算
//按位运算
System.Console.WriteLine("");
System.Console.WriteLine("按位运算");
int j=10;//0000 1010
int k=6; //0000 0110
System.Console.WriteLine($"j & k ={j&k}");
System.Console.WriteLine($"j | k ={j|k}");
System.Console.WriteLine($"j ^ k ={j^k}");
//移位运算
System.Console.WriteLine("");
System.Console.WriteLine("移位运算");
System.Console.WriteLine($"j<<3 = {j<<3}");
System.Console.WriteLine($"k>>1 = {k>>1}");
nameof 以字符串值的形式返回变量
sizeof 返回简单类型的字节大小
//nameof sizeof
System.Console.WriteLine("");
System.Console.WriteLine("---nameof sizeof ---");
int age=1000;
System.Console.WriteLine($"var age,s name is {nameof(age)}");
新的写法 避免了age变量名更改后,忘记更改字符串"age",因为字符串编译器是不错提示错误的
System.Console.WriteLine($"var int,s size is {sizeof(int)}");