zoukankan      html  css  js  c++  java
  • c#6.0/7.x新特性(二)

    c# 7.0

    out参数增强

    允许out参数在函数调用中直接定义,out参数不需要初始化,很多时候在传入函数时才是第一次需要被使用的。
    这个增强方便不少

    if (!int.TryParse(input, out int result))
    {    
        return null;
    }
    
    return result;
    

    Tuples元组类型

    好像在python中,是叫做元组。这是c#语言新增加的类型支持。
    虽然以前也有,但是功能并不完善。
    几种方式的元组创建:

    var letters = ("a", "b");  //Item1, Item2
    (string Alpha, string Beta) namedLetters = ("a", "b");
    var alphabetStart = (Alpha: "a", Beta: "b");
    

    作为一种类型,可以直接作为函数的参数,或者返回类型:

    private static (int Max, int Min) Range(IEnumerable<int> numbers)
    {
        int min = int.MaxValue;
        int max = int.MinValue;
        foreach(var n in numbers)
        {
            min = (n < min) ? n : min;
            max = (n > max) ? n : max;
        }
        return (max, min);
    }
    

    元组的解析

    通过以下方式,可以直接将元组的两个参数放到max和min中:

    (int max, int min) = Range(numbers);
    

    这叫做Deconstruct,不知道翻译成啥好。。。

    丢弃变量

    这个讲的是,在上一个元组解构的特性,或者是调用的函数有out参数时,我们必须为每一个位置都定义一个变量。
    而有些时候,有的变量我们其实用不到,这个时候可以使用只写变量_占位

    using System;
    using System.Collections.Generic;
    
    public class Example
    {
       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
    

    其实所有有不想要的变量又必须填一个进去时,都可以用_,这个变量可以被任何时候赋值,但是不能用在其他场景。

    格式匹配

    字面不是很容易理解,含义是,根据不同条件(一般是类型)匹配某一段语句执行。
    类似switch或者is语句,但是可以在类型后,定义一个新的变量代表类型转换后的值,在接下来使用:

    IS格式

    public static int DiceSum2(IEnumerable<object> values)
    {
        var sum = 0;
        foreach(var item in values)
        {
            if (item is int val)
                sum += val;
            else if (item is IEnumerable<object> subList)
                sum += DiceSum2(subList);//否则,这里可能需要增加一个强制类型转换的语句
        }
        return sum;
    }
    

    switch语句

    public static int DiceSum4(IEnumerable<object> values)
    {
        var sum = 0;
        foreach (var item in values)
        {
            switch (item)
            {
                case 0:
                    break;
                case int val:
                    sum += val;
                    break;
                case IEnumerable<object> subList when subList.Any():
                    sum += DiceSum4(subList);
                    break;
                case IEnumerable<object> subList:
                    break;
                case null:
                    break;
                default:
                    throw new InvalidOperationException("unknown item type");
            }
        }
        return sum;
    }
    

    引用类型作为返回类型

    类似参数中的ref,有时候我们需要返回值也是ref类型,可以在返回后进行修改,c#增加了这种支持:

    public static ref int Find3(int[,] matrix, Func<int, bool> predicate)
    {
        for (int i = 0; i < matrix.GetLength(0); i++)
            for (int j = 0; j < matrix.GetLength(1); j++)
                if (predicate(matrix[i, j]))
                    return ref matrix[i, j];
        throw new InvalidOperationException("Not found");
    }
    ref var item = ref MatrixSearch.Find3(matrix, (val) => val == 42);
    Console.WriteLine(item);
    item = 24;
    Console.WriteLine(matrix[4, 2]);
    

    注意函数的返回类型,以及接受函数返回值的参数定义都必须带有ref关键字,单独的var关键字不能代表引用

    局部函数

    即在函数内定义函数。
    看到有两个相对有用的地方

    • 增加代码可读性,有的私有函数仅供一个函数调用,这样将其移入调用函数内部,方便理解代码
    • 异步函数抛出异常:将异步操作放在内部函数中,前面的判断操作可以立刻返回
    public Task<string> PerformLongRunningWork(string address, int index, string name)
    {
        if (string.IsNullOrWhiteSpace(address))
            throw new ArgumentException(message: "An address is required", paramName: nameof(address));
        if (index < 0)
            throw new ArgumentOutOfRangeException(paramName: nameof(index), message: "The index must be non-negative");
        if (string.IsNullOrWhiteSpace(name))
            throw new ArgumentException(message: "You must supply a name", paramName: nameof(name));
    
        return longRunningWorkImplementation();
    
        async Task<string> longRunningWorkImplementation()
        {
            var interimResult = await FirstWork(address);
            var secondResult = await SecondStep(index, name);
            return $"The results are {interimResult} and {secondResult}. Enjoy.";
        }
    }
    

    expression-bodied成员

    增加了更多支持,如初始化和析构函数,getter/setter等

    // 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";
    }
    

    新增的异步返回类型ValueTask

    除了Task/Void以外,ValueTask也可以作为async函数的返回类型,相比Task,这个类型属于值类型,相比于Task的引用类型,轻量很多

    增加_作为数字中的分割符

    这是一个便于书写和阅读代码的特征,_可以用在任何数字表达式中,仅为了看起来能够区分数字位数等信息,对数值没有任何影响:

    public const int ThirtyTwo = 0b0010_0000;
    public const int SixtyFour = 0b0100_0000;
    public const int OneHundredTwentyEight = 0b1000_0000;
    public const double AvogadroConstant = 6.022_140_857_747_474e23;
    public const decimal GoldenRatio = 1.618_033_988_749_894_848_204_586_834_365_638_117_720_309_179M;
    
  • 相关阅读:
    利用 Makefile 写的小程序
    linux内核学习之进程管理------task_struct结构体
    智能指针
    explicit 关键字
    ant脚本编写
    FROM_UNIXTIME 格式化MYSQL时间戳函数
    Dubbo架构设计详解-转
    Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)转
    SiteMesh详解
    sitemesh使用步骤
  • 原文地址:https://www.cnblogs.com/mosakashaka/p/12608201.html
Copyright © 2011-2022 走看看