- 为什么要从基础看起
- 从.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
{ [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 = 2var 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;
标签: