当前位置: 首页 > news >正文

asp 免费网站模板扫黄打非网站建设

asp 免费网站模板,扫黄打非网站建设,网页版qq空间登录入口官网,国内最厉害的公关团队从C#9.0开始#xff0c;我们有了一个有趣的语法糖#xff1a;记录(record)   为什么提供记录#xff1f; 开发过程中#xff0c;我们往往会创建一些简单的实体#xff0c;它们仅仅拥有一些简单的属性#xff0c;可能还有几个简单的方法#xff0c;比如DTO等等#xf…从C#9.0开始我们有了一个有趣的语法糖记录(record)   为什么提供记录 开发过程中我们往往会创建一些简单的实体它们仅仅拥有一些简单的属性可能还有几个简单的方法比如DTO等等但是这样的简单实体往往又很有用我们可能会遇到一些情况 比如想要克隆一个新的实体而不是简单的引用传递   比如想要简单的比较属性值是否都一致 比如在输出我们希望得到内部数据结构而不是简单的甩给我们一个类型名称 其实这说的有些类似结构体的一些特性那为什么不直接采用结构体来实现呢这是因为结构体有它的一些不足   1、结构体不支持继承2、结构体是值传递过程因此这意味着大量的结构体拥有者相同的数据但是占用这不同内存3、结构体内部相等判断使用ValueType.Equals方法它是使用反射来实现因此性能不快 而引用类型记录正好弥补了这些缺陷。 在C#9.0中我们使用record关键字声明一个记录类型它只能是引用类型   public record Animal; 从C#10开始我们不仅有引用类型记录还有结构体记录 //使用record class声明为引用类型记录class关键字是可选的当缺省时等价于C#9.0中的record用法public record Animal;//等价于public record class Animal;//使用record struct声明为结构体类型记录public record struct Animal;//也可使用readonly record struct声明为只读结构体类型记录public readonly record struct Animal; 至于它们是什么区别上和普通class、struct有什么不一样我们慢慢道来 引用类型记录 引用类型记录不是一种新的类型它是class用法的一个新用法新的语法糖也就是说record class是引用类型这个在C#9.0中没有record class的写法直接使用record。 先看看引用类型记录是什么样子的首先是无构造参数的记录 //无构造参数无其它方法属性等public record Animal;//实例化var animal new Animal(); 在编译时会生成对应的class大致等价于下面的例子   public class Animal : IEquatableAnimal{public Animal() { }protected Animal(Animal original) { }protected virtual Type EqualityContract typeof(Animal);public virtual Animal Clone$() new Animal(this);public virtual bool Equals(Animal? other) (other ! null) (this.EqualityContract other.EqualityContract);public override bool Equals(object obj) this.Equals(obj as Animal);public override int GetHashCode() EqualityComparerType.Default.GetHashCode(this.EqualityContract);protected virtual bool PrintMembers(StringBuilder builder) false;public override string ToString(){StringBuilder builder new StringBuilder();builder.Append(Animal);builder.Append( { );if (this.PrintMembers(builder)){builder.Append( );}builder.Append(});return builder.ToString();}public static bool operator (Animal r1, Animal r2) (r1 r2) || ((r1 ! null) r1.Equals(r2));public static bool operator !(Animal r1, Animal r2) !(r1 r2);} 可以看到除了几个相比较的方法那么这个记录的作用几乎等价于object了这里有一个Clone$()方法这是编译器生成的作用后面再解释。 再看看有构造参数的记录 //有构造参数无其它方法属性等public record Person(string Name, int Age);//实例化var person new Person(zhangsan, 1); 注上面的定义可能会报错 据说这是VS2019的一个小BUG因为记录会生成 init setter解决办法是添加一个命名空间是System.Runtime.CompilerServices名称是IsExternalInit类就行了   namespace System.Runtime.CompilerServices{class IsExternalInit{}} 有构造参数的记录在编译时会生成对应的class大致等价于下面的例子 public class Person : IEquatablePerson{public Person(string Name, int Age){this.Name Name;this.Age Age;}protected Person(Person original){this.Name original.Name;this.Age original.Age;}protected virtual Type EqualityContract typeof(Person);public string Name { get; init; }public int Age { get; init; }public virtual Person Clone$() new Person(this);public void Deconstruct(out string Name, out int Age) (Name, Age) (this.Name, this.Age);public virtual bool Equals(Person? other) (other ! null) (this.EqualityContract other.EqualityContract) EqualityComparerstring.Default.Equals(this.Name, other.Name) EqualityComparerint.Default.Equals(this.Age, other.Age);public override bool Equals(object obj) this.Equals(obj as Person);public override int GetHashCode() (((EqualityComparerType.Default.GetHashCode(this.EqualityContract) * -1521134295) EqualityComparerstring.Default.GetHashCode(this.Name)) * -1521134295) EqualityComparerint.Default.GetHashCode(this.Age);protected virtual bool PrintMembers(StringBuilder builder){builder.Append(Name);builder.Append( );builder.Append(this.Name);builder.Append(, );builder.Append(Age);builder.Append( );builder.Append(this.Age.ToString());return true;}public override string ToString(){StringBuilder builder new StringBuilder();builder.Append(Person);builder.Append( { );if (this.PrintMembers(builder)){builder.Append( );}builder.Append(});return builder.ToString();}public static bool operator (Person r1, Person r2) (r1 r2) || ((r1 ! null) r1.Equals(r2));public static bool operator !(Person r1, Person r2) !(r1 r2);} 可以看到相比无构造参数的记录有构造参数的记录将构造参数生成了属性setter是init而且Equals、GetHashCode、ToString等方法重载都有这几个属性参与。 除此之外还生成了一个Deconstruct方法因此有构造参数的记录就具有解构能力。另外这里也同样生成了一个Clone$方法。 接下来看看记录的这些属性和方法 1、构造函数和属性 记录会根据给定的参数生成一个构造函数同时为每一个构造参数生成一个属性为了规范参数应采用匈牙利命名法首字符大写比如上面的Animal记录等价于   public class Animal : IEquatableAnimal{public Animal(string Name, int Age){this.Name Name;this.Age Age;}public string Name { get; init; }public int Age { get; init; }//其他方法属性} 这里的属性的setter是init也就是说记录具有不可变性记录一旦初始化完成那么它的属性值将不可修改可以通过反射修改。 另外记录允许我们自定义构造方法和属性但是需要遵循   1、记录在编译时会根据构造参数生成一个默认的构造函数默认构造函数不能被覆盖如果有自定义的构造函数那么需要使用this关键字初始化这个默认的构造函数2、记录中可以自定义属性自定义属性名可以与构造参数名重名也就是说自定义属性可以覆盖构造参数生成的属性此时对应构造参数将不起任何作用但是我们可以通过属性指向这个构造参数来自定义这样一个属性 比如     public record Person(string Name, int Age){//自定义构造函数需要使用this初始化默认构造函数public Person(string Name) : this(Name, 18){ }//覆盖构造参数中的Age属性不用是init可以自定义,public也可以改成internal等等internal int Age { get; set; } Age;//这个赋值很重要如果没有构造函数中的参数值将不会给到属性也就是说构造函数中的Age不起任何作用//额外的自定义属性public DateTime Birth { get; set; }}//等价于public class Person : IEquatablePerson{public Person(string Name) : this(Name, 18){ }public Person(string Name, int Age){this.Name Name;this.Age Age;}public string Name { get; init; }internal int Age { get; set; }//Age改变//额外的自定义属性public DateTime Birth { get; set; }//其他方法及属性} 从上面可以看到虽然记录具有不可变性但是我们可以通过自定义属性来覆盖原来的行为让其属性变为可修改的Age属性有原来的public和init变为internal和set。 此外在创建一个记录时可以给构造参数指定一些特性标识在编译时会用这些特性给到生成的对应属性如   public record Person([property: JsonPropertyName(name)] string Name, [property: JsonPropertyName(age)] int Age);//等价于public class Person : IEquatablePerson{[JsonPropertyName(name)]public string Name { get; set; }[JsonPropertyName(age)]public int Age { get; set; }//其他方法及属性} 其中property表示特性加在属性上field表示特性加在字段上param表示特性加在构造函数的参数上 2、记录可以解构 上面的例子可以看到每个记录在编译时会针对构造参数生成一个Deconstruct 方法因此记录天生就支持解构   Person person new Person(zhangsan, 21);var (name, age) person;Console.WriteLine($name{name},age{age});//namezhangsan,age21 注解构只针对默认构造函数的构造参数不计算自定义的属性和构造函数如果需要我们还可以重载自己的解构Deconstruct方法 3、记录可以继承   记录可继承但是需要遵循   1、一条记录可以从另一条记录继承但不能从一个类中继承一个类也不能从一个记录继承2、继承的子记录必须声明父记录中各参数 例如   public record Person(string Name, int Age);public record Teacher(string Phone, int Age, string Name) : Person(Name, Age);public record Student(string Grade, int Age, string Name) : Person(Name, Age); 4、值相等性 值相等性一般是值类型的一个概念而记录是引用类型要实现值相等性主要通过三个方面来实现 重写Object的Equals和GetHashCode方法重写运算符  和 !实现了IEquatableT接口 重写Object的Equals方法和重写运算符 、!很好理解因为引用类型在使用Equals方法或者运算符 、!作判断时是根据对象是否是同一个对象的引用而返回true或者false例如  public record Person(string Name, int Age);static void Main(string[] args){//一般引用类型var exception1 new Exception();var exception2 exception1;Console.WriteLine(exception1.Equals(exception2));//trueConsole.WriteLine(exception1 exception2);//trueConsole.WriteLine(exception1.Equals(new Exception()));//falseConsole.WriteLine(exception1 new Exception());//false//记录var person1 new Person(zhangsan, 18);var person2 person1;Console.WriteLine(person1.Equals(person2));//trueConsole.WriteLine(person1 person2);//trueConsole.WriteLine(person1.Equals(new Person(zhangsan, 18)));//trueConsole.WriteLine(person1 new Person(zhangsan, 18));//true} 对于实现了IEquatableT接口是为了让记录在泛型集合中如DictionaryTKey,TValue, ListT等在使用Contains, IndexOf, LastIndexOf, Remove等方法时可以像stringintbool等类型一样对待例如   public record Person(string Name, int Age);static void Main(string[] args){//一般引用类型ListException exceptions new ListException() { new Exception() };Console.WriteLine(exceptions.IndexOf(new Exception()));//-1Console.WriteLine(exceptions.Contains(new Exception()));//falseConsole.WriteLine(exceptions.Remove(new Exception()));//false//记录ListPerson persons new ListPerson() { new Person(zhangsan, 18) };Console.WriteLine(persons.IndexOf(new Person(zhangsan, 18)));//0Console.WriteLine(persons.Contains(new Person(zhangsan, 18)));//trueConsole.WriteLine(persons.Remove(new Person(zhangsan, 18)));//true} 换句话说虽然记录是引用类型但是我们应该将记录按值类型一样去使用。 注意   1、实现的IEquatableT接口的Equals方法和重写的GetHashCode方法中使用的属性不仅仅是构造参数对应的属性还包含自定义的属性、继承的属性包括publicinternalprotectedprivate但是需要有get获取器2、无论是重写Object的Equals方法还是重写运算符 和 !最终都是调用实现的IEquatableT接口的Equals方法 虽然记录的值相等性很好用但是这有个问题因为记录可继承那么如果父子记录的属性值一样如果判定他们相同显然不合理因此编译时额外生成了一个EqualityContract属性   1、EqualityContract属性指向当前的记录类型Type使用protected修饰2、如果记录没有从其它记录继承那么EqualityContract属性会带有virtual修饰否则将会使用override重写3、如果记录指定为sealed即不可派生那么EqualityContract属性会带有sealed修饰 为了保证父子记录的差异性在实现的IEquatableT接口的Equals方法中处理判断属性值相同外还会判断记录类型是否一致即EqualityContract属性。 那如果说我们需要只考虑属性值而不考虑类型时需要判断他们相等这时只需要重写EqualityContract属性将它指向同一个Type即可。 此外可以自定义Equals方法这样编译时就不会生成Equals方法。 5、非破坏性变化with 因为记录是引用类型而属性的setter是init因此当我们需要克隆一个记录时就出现困难了我们可以通过自定义属性来修改setter来实现但这不是记录的初衷。 记录可以使用with关键字来实现非破坏性的变化   public record Person(string Name, DateTime Birth, int Age, string Phone, string Address);static void Main(string[] args){//初始化了一个对象Person person new(zhangsan, new DateTime(1999, 1, 1), 22, 13987654321, 中国);//如果想改下地址因为记录的不可变性不能直接使用属性修改//person.Address 中国深圳;//报错//方法一可以重新初始化但是不方便person new(person.Name, person.Birth, person.Age, person.Phone, 中国深圳);//方法二可以使用with关键字person person with { Address 中国深圳 };//可以使用with关键字克隆一个对象var clone person with { };Console.WriteLine(clone person);//trueConsole.WriteLine(ReferenceEquals(clone, person));//false} 使用with关键字时会先调用Clone$()方法来创建一个对象然后对这个对象进行指定属性的初始化这就是最开始的例子中Clone$()方法的作用   person person with { Address 中国深圳 };//在编译后等价于var tempperson.Clone$();temp.Address 中国深圳;person temp; 在写代码时我们当然不能显式的调用Clone$()方法因为名称不合法它是编译器生成的Clone$()方法其实就是调用一个构造函数来实现初始化的这表示我们可以通过自定义或者重写这个构造函数来实现我们自己的逻辑   public class Person : IEquatablePerson{protected Person(Person original){this.Name original.Name;this.Age original.Age;}public virtual Person Clone$() new Person(this);//其他方法属性} 注意传入构造函数的参数是原始对象然后使用原始对象中的属性值来进行初始化如果属性值是一个引用类型那么它将进行浅复制过程。 注这里with用法针对引用类型记录值类型记录的with参考后文 6、内置格式化 记录还重写了ToString可以方便查看输出格式默认是   记录类型 { 属性名1 属性值1, 属性名2 属性值2, ...} 例如   public record Person(string Name, int Age);static void Main(string[] args){//初始化了一个对象Person person new(zhangsan, 22);Console.WriteLine(person);//输出Person { Name zhangsan, Age 22 }} 编译器还合成了一个PrintMembers方法如果我们有自己提供PrintMembers方法编译器就不会合成了所以如果我们想要实现自己的格式化只需要实现自己的PrintMembers方法而不用重写ToString方法。   值类型记录 注值类型记录只针对C#10及以后的版本有效 值类型记录也就是结构体记录大体上值类型记录与引用类型记录的区别就跟值类型与引用类型的区别差不多所以具体不介绍可以参考上面引用类型的介绍这里只具体介绍它们的区别。 值类型记录又分为两种record struct和readonly record struct这里结合record class来看看它们的区别 比如有三个record   public record class Point1(double X, double Y); public readonly record struct Point2(double X, double Y); public record struct Point3(double X, double Y); 这里Point1是record classPoint2是readonly record structPoint3是record struct经过编译它们等价于下面的三个类和结构体方法体去掉了具体可参考上面引用类型记录   可以看到这三种类型的记录主要有共同点有   1、对记录的参数分别生成了属性2、生成了一个包含记录所有属性的构造函数3、重写了 Object.Equals(Object)方法和Object.GetHashCode()方法4、实现了System.IEquatableT接口5、实现了和!运算操作6、实现了Deconstruct方法而实现解构操作7、重写了Object.ToString()方法以及创建了一个PrintMembers用于序列化但是PrintMembers有些许区别共同点没什么好说的参考上面引用类型介绍就可以了接下来说说不同点 1、record class和readonly record struct生成的属性是get和init标识也就是说它们的对象是只读的而record struct生成的属性是get和set标识也就是说它的对象是可读可写的 例如 var point1 new Point1(1, 2);point1.X 2;//报错var point2 new Point2(1, 2);point2.X 2;//报错var point3 new Point3(1, 2);point3.X 2;//编译通过 2、在构造函数上record class会生成两个构造函数一个是protected修饰用于Clone$()方法克隆一个对象一个public修饰包含所有的构造参数而readonly record struct和record struct只包含一个public修饰包含所有的构造参数的构造函数但是因为它们的本质还是结构体因此默认会有一个空构造函数因此在创建时有区别   //创建时需要指定所有的参数protected修饰的构造函数不能在记录及子记录外使用var point1 new Point1(1, 2);//除了可以指定所有参数的构造函数还可以使用空构造函数初始化var point2 new Point2(1, 2);point2 new Point2();var point3 new Point3(1, 2);point3 new Point3(); 3、record class类型记录会生成一个Clone$()方法它通过调用一个protected的构造函数来克隆出一个新的引用对象而我们可以通过自定义或者重写这个protected的构造函数的构造函数来实现我们自己业务逻辑。 其实这个Clone$()方法是在with关键字中使用的   var point1 new Point1(1, 2);var point point1 with { X 2 };//等价于var point1 new Point1(1, 2);var point point1.Clone$();point.X 2;//注编译时给point.X赋值会报错因为init这里只是说明 而对于readonly record struct和record struct类型记录因为它们的本质是struct天生是值复制的因此就不需要这么一个Clone$()方法了与此对应的是结构体默认会有空构造函数C#10。 var point2 new Point2(1, 2);var point point2 with { X 2 };//等价于var point point2;//struct是值复制过程point.X 2; //注编译时给readonly record struct声明的属性赋值会报错而给record struct声明的属性赋值不会报错这里只是说明4、record structreadonly record structrecord class都可以拥有自定义属性但是有些许区别 1、record class按类中的属性规则去定义2、record struct按结构体中的属性规则去定义此外定义的属性必须进行初始化3、readonly record struct按结构体中的属性规则去定义此外定义的属性必须进行初始化而且定义的属性只能是只读的 例如   public record class Point1(double X, double Y){public double Z { get; set; }}public readonly record struct Point2(double X, double Y){public double Z { get; } default;//必须初始化此外readonly修饰所以只能只读}public record struct Point3(double X, double Y){public double Z { get; set; } default;//必须初始化} 5、record structreadonly record structrecord class都实现了System.IEquatableT接口而且重写了Object.Equals(Object)方法本质上是通过System.IEquatableT接口来实现但是record class中实现的Equals方法除了比较属性以外还会比较记录的类型是否一致即比较EqualityContract属性这一点可以参考上面介绍的引用类型记录的值相等性部分而对于record structreadonly record struct在编译时并没有生成一个EqualityContract属性在实现的Equals方法也只是比较了属性值没有比较类似是否一致。 其实想想结构体只能实现接口而不能从另一个结构体派生因此在在实现的Equals方法自然就没有进行类型判断的必要了。 6、record structreadonly record structrecord class都重写了Object.ToString()方法而且都是通过创建了一个PrintMembers方法来实现的但是在PrintMembers方法上表现的行为不一致这是一点细节了解即可。   1、如果记录是结构体记录即record struct和readonly record struct或者使用sealed关键字修饰那么生成的PrintMembers方法是private bool PrintMembers(StringBuilder builder);2、如果记录没有使用sealed关键字修饰且记录直接派生自Object即没有派生自一个父记录那么生成的PrintMembers方法是protected virtual bool PrintMembers(StringBuilder builder);3、如果记录派生自一个父记录那么生成的PrintMembers方法是protected override bool PrintMembers(StringBuilder builder);总结 记录是一个语法糖本质上还是class或者struct它只编译时生效运行时并没有记录这个东西此外根据官网介绍记录不适合在EntityFrameworkCore中使用毕竟它重写了Equals方法和相等运算和!这样可能会对EntityFrameworkCore的实体跟踪机制造成影响。
http://www.dnsts.com.cn/news/9796.html

相关文章:

  • 一个网站多个域名的seo优化移动应用开发专业
  • 搜索的网站后大拇指分享数量不见了长沙网站建设索王道下拉
  • 外国服务器的网站西宁网站建设西宁
  • 网站搭建软件d北京做视觉网站
  • 网站建设东莞长安镇微信群投票网站怎么做
  • 怎么分析竞争对手网站做家教的正规网站
  • 修改dns连接外国网站怎么制作小视频
  • 要个网站哪里有做网站的单位
  • 承接网站建设广告语广州市平安建设 网站
  • 有没有什么网站专门帮人做问卷wordpress 轻论坛
  • 网站宣传工作ui设计周末培训学校
  • 建设企业网站的好处是什么h5网站设计方案
  • 网站建设培训班南宁苏州苏州设计公司
  • 用自己的电脑做服务器建网站名人朋友圈网页版qq登录入口
  • 做旅游的海报图片网站上海好的网站设计公司有哪些
  • 餐饮网站建设公司黄骅港赶海攻略
  • 网站怎么显示建设中房产信息网上自助查询
  • 怎么做电力设计公司网站长图片生成器在线制作
  • 北京建设高端网站进贤网站建设
  • 医院网站HTML5把asp.net写的网站别人怎么访问
  • 太仓智能网站开发墨刀做网站上下滑动的交互
  • 用npp做网站网站备案号是什么意思
  • 好建网站做细分领域的同城网站
  • 夸克网站免费进入建立一个app平台需要多少钱
  • 自己做网站开发24小时学会网站建设
  • 织梦网站导航浮动网站打开速度
  • 东莞建设网 东莞市住房和城乡建设局门户网站产品开发设计流程
  • 网站开发项目需求方案残疾人无障碍网站建设
  • 高校网站建设的问题及对策地推是什么意思
  • 重庆金融网站建设国外家具设计网站大全