zoukankan      html  css  js  c++  java
  • C# 基础复习三 C#7

    out 变量

    (以前必须在外面定义一行才可以使用)

    if (int.TryParse(input, out int result))
        Console.WriteLine(result);

    元组

    元组(Tuple)在 .Net 4.0 的时候就有了,但元组也有些缺点,如:
    1)Tuple 会影响代码的可读性,因为它的属性名都是:Item1,Item2.. 。
    2)Tuple 还不够轻量级,因为它是引用类型(Class)。
    备注:上述所指 Tuple 还不够轻量级,是从某种意义上来说的或者是一种假设,即假设分配操作非常的多。
    C# 7 中的元组(ValueTuple)解决了上述两个缺点:
    1)ValueTuple 支持语义上的字段命名。
    2)ValueTuple 是值类型(Struct)。

    • 如何创建一个元组?
     var tuple = (1, 2);                            //使用语法糖创建元组
     var tuple2 = ValueTuple.Create(1, 2);         // 使用静态方法【Create】创建元组
     var tuple3 = new ValueTuple<int, int>(1, 2);  // 使用 new 运算符创建元组
    WriteLine($"first:{tuple.Item1}, second:{tuple.Item2}, 上面三种方式都是等价的。");
    • 如何创建给字段命名的元组?
      以前的元组元素只能是item1 itme2 ,现在可以起有意义的名字了
    // 左边指定字段名称
    (string Alpha, string Beta) namedLetters = ("a", "b");
    Console.WriteLine($"{namedLetters.Alpha}, {namedLetters.Beta}");
    //右边指定字段名称
    var alphabetStart = (Alpha: "a", Beta: "b");
    Console.WriteLine($"{alphabetStart.Alpha}, {alphabetStart.Beta}");
    // 左右两边同时指定字段名称
     (int one, int two) tuple3 = (first: 1, second: 2);    /* 此处会有警告:由于目标类型(xx)已指定了其它名称,因为忽略元组名称xxx */
    WriteLine($"first:{tuple3.one}, second:{tuple3.two}");
    //注:左右两边同时指定字段名称,会使用左边的字段名称覆盖右边的字段名称(一一对应)。
    //原理解析:上述给字段命名的元组在编译后其字段名称还是:Item1, Item2...,即:“命名”只是语义上的命名
    • 什么是解构? deconstructing the tuple
      原理解析:解构元组就是将元组中的字段值赋值给声明的局部变量(编译后可查看)
    (int max, int min) = Range(numbers);
    Console.WriteLine(max);
    Console.WriteLine(min);
    
    //下面的例子是说了返回值命名 提高代码的可读性
       static void Main(string[] args)
        {
            Tuple<int, int> result = GetMessageModel();
            Console.WriteLine(result.Item1);//不知道Item1的具体名称是什么
            Console.WriteLine(result.Item2);
            var result2 = GetMessageModel1();
            Console.WriteLine(result2.min);//现在有了具体的名字
            Console.WriteLine(result2.max);
             var (max, _)  = GetMessageModel1();//弃元的一种
             Console.WriteLine(max);
            Console.WriteLine("Hello World!");
        }
            static Tuple<int, int> GetMessageModel()
            {
                Tuple<int, int> result = new Tuple<int, int>(1, 5);
                return result;
            }
            static (int max, int min) GetMessageModel1()
            {
                return (1, 5);
            }
    • 解构可以应用于 .Net 的任意类型,但需要编写 Deconstruct 方法成员(实例或扩展)
    public class Point
       {
           public Point(double x, double y)
               => (X, Y) = (x, y);
           public double X { get; }
           public double Y { get; }
           public void Deconstruct(out double x, out double y) =>
               (x, y) = (X, Y);
       }
       //You can extract the individual fields by assigning a Point to a tuple:
       var p = new Point(3.14, 2.71);
    (double X, double Y) = p;

    弃元

    用途:
    定义元组或者自定义数据 我只需要第四个值跟第6个值 其它的我不关心;

        public static void Main()
        {
            var (_, _, _, pop1, _, pop2) = QueryCityDataForYears("New York City", 1960, 2010);
            Console.WriteLine($"Population change, 1960 to 2010: {pop2 - pop1:N0}");
        }
        private static (string, double, int, int, int, int) QueryCityDataForYears(string name, int year1, int year2)
        {
            int population1 = 0, population2 = 0;
            double area = 0;
            if (name == "New York City")
            {
                area = 468.48;
                if (year1 == 1960)
                {
                    population1 = 7781984;
                }
                if (year2 == 2010)
                {
                    population2 = 8175133;
                }
                return (name, area, year1, population1, year2, population2);
            }
            return ("", 0, 0, 0, 0, 0);
        }
    // The example displays the following output:
    // Population change, 1960 to 2010: 393,149
    • 当使用外参的时候
        string l_strDate = "2019-01-01";
        if (DateTime.TryParse(l_strDate,out _)) //以前需要写..
        {
            Console.WriteLine(DateTime.Parse(l_strDate));
        }
    • 在模式匹配操作 is switch语句中
    public static void Main()
       {
          object[] objects = { CultureInfo.CurrentCulture,
                               CultureInfo.CurrentCulture.DateTimeFormat,
                               CultureInfo.CurrentCulture.NumberFormat,
                               new ArgumentException(), null };
          foreach (var obj in objects)
             ProvidesFormatInfo(obj);
       }
       private static void ProvidesFormatInfo(object obj)        
       {
          switch (obj)
          {
             case IFormatProvider fmt:
                Console.WriteLine($"{fmt} object");
                break;
             case null:
                Console.Write("A null object reference: ");
                Console.WriteLine("Its use could result in a NullReferenceException");
                break;
             case object _:
                Console.WriteLine("Some object type without format information");
                break;
          }
       }
    • 数字,二进制的分隔符 增强文本可读性
    // 二进制文本:
    public const int Sixteen = 0b0001_0000;
    // 数字分隔符:
    public const long BillionsAndBillions = 100_000_000_000;
    • 独立弃元
            private static void ShowValue(int _)
            {
                byte[] arr = { 0, 0, 1, 2 };
                _ = BitConverter.ToInt32(arr, 0);
                Console.WriteLine(_);
            }

    模式匹配

    现在可以在匹配一个类型时,自动转换为这个类型的变量,如果转换失败,这个变量就赋值为默认值(null或0)

    if (input is int count) //
        sum += count;
    public static int SumPositiveNumbers(IEnumerable<object> sequence)
    {
        int sum = 0;
        foreach (var i in sequence)
        {
            switch (i)
            {
                case 0:
                    break;
                case IEnumerable<int> childSequence: //模式匹配  匹配是 IEnumerable<int> 类型的
                {
                    foreach(var item in childSequence)
                        sum += (item > 0) ? item : 0;
                    break;
                }
                case int n when n > 0: //模式匹配  匹配是int 类型的
                    sum += n;
                    break;
                case null: //is the null pattern
                    throw new NullReferenceException("Null found in sequence");
                default:
                    throw new InvalidOperationException("Unrecognized type");
            }
        }
        return sum;
    }

    局部变量和返回结果

    我们知道 C# 的 ref 和 out 关键字是对值传递的一个补充,是为了防止值类型大对象在Copy过程中损失更多的性能。现在在C# 7中 ref 关键字得
    到了加强,它不仅可以获取值类型的引用而且还可以获取某个变量(引用类型)的局部引用。如:

    static ref int GetLocalRef(int[,] arr, Func<int, bool> func)
      {
          for (int i = 0; i < arr.GetLength(0); i++)
          {
              for (int j = 0; j < arr.GetLength(1); j++)
              {
                  if (func(arr[i, j]))
                  {
                      return ref arr[i, j];
                  }
              }
          }
          throw new InvalidOperationException("Not found");
      }
    
       int[,] arr = { { 10, 15 }, { 20, 25 } };
       ref var num = ref GetLocalRef(arr, c => c == 20);
       num = 600;
       Console.WriteLine(arr[1, 0]); //output 600

    使用方法:
    1.方法的返回值必须是引用返回

    • 声明方法签名时必须在返回类型前加上 ref 修饰
    • 每个 return 关键字后也要加上 ref 修饰,以表明是返回引用

    2.分配引用(即赋值),必须在声明局部变量前加上 ref 修饰,以及在方法返回引用前加上 ref 修饰。
    注:C# 开发的是托管代码,所以一般不希望程序员去操作指针。并由上述可知在使用过程中需要大量的使用 ref 来标明这是引用变量(编译后其实没那么多),当然这也是为了提高代码的可读性。
    总结:虽然 C# 7 中提供了局部引用和引用返回,但为了防止滥用所以也有诸多约束

    1. 你不能将一个值分配给 ref 变量
    ref int num = 10;   // error:无法使用值初始化按引用变量
    1. 你不能返回一个生存期不超过方法作用域的变量引用,如:
    public ref int GetLocalRef(int num) => ref num;   // error: 无法按引用返回参数,因为它不是 ref 或 out 参数
    1. ref 不能修饰 “属性” 和 “索引器”。
    var list = new List<int>();
     ref var n = ref list.Count;  // error: 属性或索引器不能作为 out 或 ref 参数传递

    局部函数(Local functions)

    一个函数在另外一个函数的里面

    public static IEnumerable<char> AlphabetSubset3(char start, char end)
    {
        if (start < 'a' || start > 'z')
            throw new ArgumentOutOfRangeException(paramName: nameof(start), message: "start must be a letter");
        if (end < 'a' || end > 'z')
            throw new ArgumentOutOfRangeException(paramName: nameof(end), message: "end must be a letter");
        if (end <= start)
            throw new ArgumentException($"{nameof(end)} must be greater than {nameof(start)}");
        return alphabetSubsetImplementation();
        IEnumerable<char> alphabetSubsetImplementation()
        {
            for (var c = start; c < end; c++)
                yield return c;
        }
    }

    更多的表达式方法体

    C# 6 的时候就支持表达式体成员,但当时只支持“函数成员”和“只读属性”,这一特性在C# 7中得到了扩展,它能支持更多的成员:构造函数
    、析构函数、带 get,set 访问器的属性、以及索引器。如下所示

    // Expression-bodied constructor
    public ExpressionMembersExample(string label) => this.Label = label;
    // Expression-bodied finalizer
    ~ExpressionMembersExample() => Console.Error.WriteLine("Finalized!");
    
    private string label;
    
    // Expression-bodied get / set accessors.
    public string Label
    {
        get => label;
        set => this.label = value ?? "Default label";
    }
    
    // Expression-bodied indexers
    public string this[string name] => Convert.ToBase64String(Encoding.UTF8.GetBytes(name));

    Throw expressions

    throw之前必须是一个语句,因此有时不得不写更多的代码来完成所需功能。但7.0提供了throw表达式来使代码更简洁,阅读更轻松。

    void Main()
    {
        // You can now throw expressions in expressions clauses.
        // This is useful in conditional expressions:
    
        string result = new Random().Next(2) == 0 ? "Good" : throw new Exception ("Bad");
        result.Dump();
    
        Foo().Dump();
    }
    
    public string Foo() => throw new NotImplementedException();

    扩展异步返回类型(Generalized async return types)

    以前异步的返回类型必须是:Task、Task、void,现在 C# 7 中新增了一种类型:ValueTask,如下所示:

    public async ValueTask<int> Func()
    {
        await Task.Delay(100);
        return 5;
    }

    这样可以节省空间,尤其是在循环里面

  • 相关阅读:
    git提交代码五部曲
    菜单树jstree.js插件几个主要事件汇总
    创维电视加mac过滤后连不了wifi问题(路由器为TP-link)
    Mysql和Navicat for MySQL本地运行.sql文件
    MySQL下载与安装
    js一个区域拖拽到另一个区域,拖拽后还可以排序。知识点:js插件Jquery-UI:拖拽组件draggable,放置组件droppable,排序组件sortable
    echarts基本应用-更改坐标轴文字样式、轴名称、轴刻度、轴线、轴网格、曲线(折线图)、柱体上面显示值(柱状图),鼠标悬浮提示
    boostrap的时间插件daterangepicker.js之单日期,精确到秒
    echarts用法之点击事件(圆柱体例子)
    注册界面和功能
  • 原文地址:https://www.cnblogs.com/maanshancss/p/cadbd02ddc22f89f61fc2059f47d7010.html
Copyright © 2011-2022 走看看