dotnet-csharp
- 为什么要从基础看起
- 从.net framework3.5就开始接触c#,到现在.net7的崛起,期间有大量的新技术和框架冲击着我,MVC1.0的时候放弃过,感觉无所适从,linq也是近几年才开始使用,感觉现在写代码的方式已经被时代所淘汰,因此萌生出了从头捋顺一次。
- 学习的时候并没有通过一个完整的体系去学习,而是在实践中去探索,这样带来一个问题,什么是最佳实践,应该如何去做技术选型。微软创造出了很多轮子,哪一个才是适合的?希望能从微软的官方文档中寻找到答案
.NET体系结构
-
简而言之,.NET是公共语言运行时(CLR)的虚拟执行系统和一组类库的集合
-
CLR:公共语言结构(CLI)国际标准的实现
-
CLI:创建执行和开发环境的基础,语言和库可以无缝的协同工作。
-
c#编写的代码可以编译成复核CLI规范的中间语言(IL),IL代码和资源存储在.dll的程序集中
-
程序运行流程
- 程序集加载到CLR中
- CLR直接执行实时编译(JIT),将IL代码转换为本机指令
- CLR可提供自动垃圾回收,异常处理和资源管理的服务
CLR执行的代码成为"托管代码",而"非托管代码"被编译成面向特定平台的本机语言
-
优势
- 底层编译环境一样,c#生成的IL代码可与.Net其他语言进行交互(底层一样)
- .NET还有大量的库,可以通过引用命名空间来使用
类型和遍历
-
值类型和引用类型
-
值类型
-
简单类型(char是值类型),枚举类型(enum),结构类型(struct),null的值类型(int?),元组值类型
-
元组值类型(c# 7.0)
// 1.直接声明 (double, int) t1 = (4.5, 3) Cosole.WriteLine($"elements is {t1.Item1} and {t1.Item2}"); // 2.有变量名 (double Sum, int Count) t2 = (4.5, 3); Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}.");
-
-
引用类型
- 类类型:基类为object的继承类,string(UTF-16代码单元序列),用户定义类(class C{})
- 接口类型(interface I{})
- 数组 int[], int[,] int[i] [j]
- 委托类型(delegate int D{})
- record类型
-
record类型(C# 9.0)
只读属性的轻量级、不可变数据类型
-
record Class(class可省略)引用类型记录
public record Params([property: JsonPropertyName("param1")] string Param1,[property:JsonPropertyName("param2")] int Param2); // 等价于 public class Person : IEquatable<Params> { [JsonPropertyName("param1")] public string Param1 { get; set; } [JsonPropertyName("param2")] public int Param2 { get; set; } } // 可继承 public record ExtParams(string Param1, int Param2 string Param3, string Param4):Params(Param1,Param2) // 与元组值类型合用 Params params = new Params("param1", 2); var (item1, item2) = params; Console.WriteLine($"item1={item1},item2={item2}");//输出:item1=item1,item2=2 // 使用with克隆 var pClone1 = params with { }; // Param1 = Param1,Param2 = 2 var pClone2 = params with { Param2=4 }; // Param1 = Param1,Param2=4 // 可拥有自定义属性 public record class Params1(double p1, double p2) { public double p3 { get; set; } }
-
record Struct(c# 10.0)值类型记录
// 与record class类似 public record struct RecordS1(int r1, int r2);
-
record Class和record Struct不同点
-
record Calss 的实例不可写 record Struct可读可写(readonly除外)
public record class RecordS1(int r1, int r2); public readonly record struct RecordS2(int r1, int r2); public record struct RecordS3(int r1, int r2); var record1 = new RecordS1(1, 2); record1.r1 = 2; //错误 var record2 = new RecordS2(1, 2); record2.r1 = 2; //错误 var record3 = new RecordS3(1, 2); record3.r1 = 2; //通过
-
拥有自定义属性不同:record Structural自定义属性必须初始化
// record class public record class RecordS1(int r1, int r2) { public int r3 { get; set; } } // readonly record struct public readonly record struct RecordS2(int r1, int r2) { public int r3 { get; } = default;//必须初始化,r3无法赋值 } // record struct public record struct RecordS3(int r1, int r2) { public int r3 { get; set; } = default;//必须初始化 }
-
-
-
-
装箱 拆箱
- 装箱 将值类型的放到引用类型中
- 拆箱 从引用类型中拿出值类型来
C#类型和成员
-
Flag特性
-
指示可以将枚举作为位域(即一组标志)处理
[Flags] public enum Seasons { None = 0, Summer = 1, Autumn = 2, Winter = 4, Spring = 8, All = Summer | Autumn | Winter | Spring } Seasons season = Seasons.All // 加上后输出season.ToString()为Summer,Autumn,Winter,Spring // 不加上输出season.ToString()为15 // 加上后如何输出15 (int)season
-
C# 程序构建基块
-
可访问性
- public 不受限制
- private 仅限于此类
- protected 仅限于此类或其派生类
- internal 仅可访问当前程序集(exe或dll)
- protected internal 同一程序集或派生类
- private protected 此类或派生类
-
属性
在类或方法上的标签
-
定义
// 创建了一个Help的属性,引用Attribute基类 public class HellpAttribute:Attribute{ string _url; string _topic; public HelpAttribute(string url)=> _url=url; public string Url => _url; public string Topic{ get => _topic; set => _topic = value; } }
-
使用
// 在类和方法上添加了属性 [Help("url")] public class Widget{ [Help("url/features", Topic = "Display")] public void Display(string text) { } }
-
解析和操作 - 利用反射
// 通过Type获得通用的属性 Type widgetType = typeof(Widget); // 获得class类的属性 object[] widgetAtt = widgetType.GetCustomAttribytes(typeof(HelpAttribute), false); if(widgetAtt.Length > 0){ HelpAttribute attr = (HelpAttribute)widgetAttr[0]; // 输出 attr.Url attr.Topic } // 获得Display方法的属性 System.Reflection.MethodInfo method = widgetType.GetMethod(nameof(Widget.Display)); object[] displayMethodAttr = method.GetCustomAttributes(typeof(HelpAttribute), false); if(displayMethodAttr.Length >0){ HelpAttribute attr = (HelpAttribute)displayMethodAttr[0]; // 输出 attr.Url attr.Topic }
-
-
弃元在元组的使用
人为取消的占位符(_)
// 方式一:返回了多个返回值,通过元组返回 var (_, _,pop1, _, pop2) = QueryData("New", 1960, 2010); static (string, double, int, int, int)QueryData(string name, int year1, int year2){ return (name, year1, year1-year2, yrear2, yrea1+yrea2); } // 方式二 使用Deconstruct(解构)方法并结合out返回元组 public class Person{ public Person(){} // 使用结构方法 public Deconstruct(out string fname, out string lname, out string city, out string state){ fname = "w"; lname = "h"; city = "wf"; state = "1"; } } var p = new Person(); var (fName, _, city, _) = p;