dotnet-sharp 笔记(二)

发布时间 2023-04-01 15:59:19作者: 摧残一生

C#新特性

  • 泛型属性

    创建属性时可直接使用泛型

    // 声明一个泛型属性
    public class GenericAttribute<T>:Attribute{}
    // 使用
    [GenericAttribute<string>()]
    public string Method()=> default;
    
  • 字符串内可插入换行符

    $"{\r\n}"

  • 原始字符串

    三个双引号开头并结尾,可以包含任意特殊字符

  • 自动默认结构

    struct中所有字段都未显示初始化任何字段都会设置默认值

  • 改进型明确赋值

    string representation = "N/A";
    if ((c != null && c.GetDependentValue(out object obj)) == true)
    {
     representation = obj.ToString(); // undesired error
    }
    // 优化后 Or, using ?.
    if (c?.GetDependentValue(out object obj) == true)
    {
     representation = obj.ToString(); // undesired error
    }
    // 再次优化后 Or, using ??
    if (c?.GetDependentValue(out object obj) ?? false)
    {
     representation = obj.ToString(); // undesired error
    }
    
    
  • AsyncMethodBuilder

    1. 对内:关联状态机和状态机执行的上下文,管理状态机的生命周期。
    2. 对外:构建一个 Task 对象,作为异步方法的返回值,并会触发该 Task 执行的完成或异常。
    3. 对于async和await的内部改进,多个await调用时按需触发
      1. 一个 Task 对象,作为异步方法的返回值。
      2. Create 方法,用来创建 AsyncMethodBuilder。
      3. Start 方法,用来启动状态机。
      4. AwaitOnCompleted/AwaitUnsafeOnCompleted 方法,用来将状态机的 MoveNext 方法注册为 async方法 内 await 的 Task 的回调。
      5. SetResult/SetException 方法,用来标记 Task 的完成状态并触发 Task 的回调。
      6. SetStateMachine 方法,用来关联状态机,不常用,编译结果也不会调用。
  • CallerArgumentExpression

    用另一个实参的文本表示形式替代

  • 优化变更

    public double CalculateSquare(double value){
    	return value * value;
    }
    // 演变
    public double CalculateSquare(doube value)=>value*value;
    // 再次演变  
    // in的引入:源兼容的更改而不是二进制的更改
    public double CalculateSquare(in double value)=>value*value;
    
  • 静态抽象接口

    // 求中间值的静态方法
    public static double MidPoint(double left, double right)=>(left+right)/(2.0);
    // 抽象后
    public static T MidPoint(T left, T right)where T:INumber<T> => (left + right)/T.CreateChecked(2);
    
  • 异步流可提供更好的方法

    await foreach 来实现异步流

  • 不为null的属性

    // 当为false时message不能为null,反之则可以为null
    public static bool IsNullOrWhiteSpace([NotNullWhen(false)] string message)
    
  • 可为空声明

    string? name;

  • 自动实现属性

    // Id不能被序列号,也不能被继承
    public clss clzz{
    	[fidle:NonSerialized]
    	public int Id{get;set;}
    }
    
  • INotifyPropertyChanged

    属性变更后触发事件

    public class Person:INotifyPropertyChanged{
    	public string FirstName{
    		get=> _firstName;
    		set{
    			if(value != _firstName){
    				_firstName = value;
    				PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FirstName)));
    			}
    		}
    	}
    	private string _firstName;
    	public event PropertyChangedEventHandler PropertyChanged;
    }
    
  • 语言集成查询(LINQ)

    • 相关关键字:from, where, in, order by(descending/descending),select

      IEnumerable<string> scoresQuery = from score in scores 
      				where score>80
      				orderby score descending
      				select $"score is {score}";
      
    • into:创建存储查询的临时表是符

      var percentQue = from country in countries
      		let percent = (int) country.Population/10000
      		// 将group的值存放到countryGroup中
      		group country by percent into countryGroup
      		where countryGroup.Key >= 20
      		order by countryGroup.Key
      		select countryGroup;
      
    • join:级联

      多个数据源进行关联或合并

      var categoryQuery = from cat in categries
      		join prod in products on cat equals prod.Category
      		select new {
      			Category = cat,
      			Name = prod.Name
      		};
      
    • 子查询

      一个表达式出现两次linq语句

      var queryGroupMax = from student in students
      		group student by student.Year into studentGroup
      		select new {
      			Level = studentGroup.Key,
      			HighestScore = (from s2 in studentGroup
      			select s2.ExamScores.Average()
      			).Max()
      		};
      
  • Expression 执行表达式树

    • 转换为委托

      Expression<Func<int>> add = () => 1+2;
      // 创建委托
      var func = add.Compile();
      // 调用委托
      var answer = func();
      Console.WriteLine(answer);
      
    • 执行幂预算例子

      // 创建一个幂是运算的二叉树
      BinaryExpression be = Expression.Power(Expression.Constant(2d),
      Expression.Constant(3d));
      // 创建lambda表达式
      Expression<Func<double>> le = Expression.Lambda<Func<double>>(be);
      // 创建委托
      Func<double> compiledExpression = le.Compile();
      // 执行委托
      double result = compiledExpression();
      // 输出的结果是8
      Console.WriteLine(result);
      
  • Expression各部分方法的说明

    // 创建一个委托方法
    Expression<Func<int, bool>> exprTree = num => num < 5;
    // 获得参数树中的第一个参数
    ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];
    // 获得操作体本身
    BinaryExpression operation = (BinaryExpression)exprTree.Body;
    // 获得传入参数
    ParameterExpression left = (ParameterExpression)operation.Left;
    // 常数体
    ConstantExpression right = (ConstantExpression)operation.Right;
    Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
     param.Name, left.Name, operation.NodeType, right.Value);
    // Decomposed expression: num => num LessThan 5
    
  • Expression代码生成转意

    // n*(n-1)**(n-2)*(n-3)*(n-4)....*2*1
    Func<int, int> factorialFunc = (n) =>
    {
         var res = 1;
         while (n > 1)
         {
         	res = res * n;
         	n--;
         }
         return res;
    };
    /////////等同于
    //入参为整数:n
    var nArgument = Expression.Parameter(typeof(int), "n");
    //方法内部参数为整数:result
    var result = Expression.Variable(typeof(int), "result");
    // 创建一个标签返回值为int
    LabelTarget label = Expression.Label(typeof(int));
    // 给参数result初始化值为1
    var initializeResult = Expression.Assign(result, Expression.Constant(1));
    // 创建一个内部方法
    var block = Expression.Block(
    	// 等同于 result = result*nArgument
    	Expression.Assign(result,
    	Expression.Multiply(result, nArgument)),
    	// nArgument -= 1
    	Expression.PostDecrementAssign(nArgument)
    );
    // 在创建一个方法体
    BlockExpression body = Expression.Block(
    	 // 声明result
         new[] { result },
         // 调用初始化方法
         initializeResult,
         // 创建循环,第一个参数是循环体,第二个参数为中断后输出的值
         Expression.Loop(
             // 判断条件
             Expression.IfThenElse(
                 // nArgument>1的时候,执行block,否则跳出 
                 Expression.GreaterThan(nArgument, Expression.Constant(1)),
                 // 正确
                 block,
                 // 错误时,携带label类型的result跳出
                 Expression.Break(label, result)
             ),
             //返回值
         	label
         )
    );