美文网首页
C#9.0终于来了,有什么新特点?带上VS一起解读吧!

C#9.0终于来了,有什么新特点?带上VS一起解读吧!

作者: 逐浪软件 | 来源:发表于2020-06-13 11:44 被阅读0次

    好消息,.NET 5.0 终于在2020年6月10日发布了第五个预览版,眼尖的同学一定看到了在这个版本中终于支持了 C# 9.0,此处有掌声,太好了!!!

    .Net5官方链接 :

    https://dotnet.microsoft.com/download/dotnet/5.0

    可以看到目前的C#9还是预览版,实现了一部分新语法供开发者提前尝鲜,从github的roslyn仓库上可以看到目前准备实现 17个新特性,现阶段已经实现了8个,其中的 In Progress 表示正在开发中。

    新特性预览

    安装必备

    下载最新的net5 sdk吧: 

    dotnet-sdk-5.0.100-preview.5.20279.10-win-x64.exe

    下载最新的 visual studio 2019 preview 2:

    https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes-preview

    找好你自己的vs版本类型哦。。。

    新特性研究

    1. Target-typed new

    这个取名一定要留给学易经的大师傅,没见过世面的我不敢造次,取得不佳影响时运,所谓 运去金成铁, 时来铁似金 ,不过大概意思就是说直接new你定义的局部变量的类型,用issues中总结的话就是:

    Summary:AllowPointp=new(x,y);

    Shippedinpreviewin16.7p1.

    接下来就是全部代码,看看使用前 和 使用后 的具体差别。

    class Program

    {

    static void Main(string[] args)

    {

    //老语法

    var person = new Person("mary","123456");

    //新语法

    Person person2 = new("mary","123456");

    Console.WriteLine($"person={person}person2={person2}");

    }

    }

    public class Person

    {

    privatestringusername;

    privatestringpassword;

    public Person(stringusername,stringpassword)

    {

    this.username = username;

    this.password = password;

    }

    public overridestringToString()

    {

    return$"username={username},password={password} \n";

    }

    }

    然后用ilspy去看看下面的il代码,是不是省略了Person,让自己心里踏实一点。

    总的来说这语法还行吧,能起到延长键盘使用寿命的功效。

    2. Lambda discard parameters

    从字面上看大概就是说可以在lambda上使用取消参数,听起来怪怪的,那本意是什么呢?有时候lambda上的匿名方法签名的参数是不需要的,但在以前必须实打实的定义,这样就会污染方法体,也就是可以在body中被访问,如下图:

    但有时候因为客观原因必须使用Func<int,int,int>这样的委托,而且还不想让方法签名的参数污染方法体,我猜测在函数式编程中有这样的场景吧,可能有点类似MVC中的EmptyResult效果。

    好了,我想你大概知道啥意思了,接下来实操一把。。。

    Funcfunc=(_, _)=>

    {

    return0;

    };

    varresult =func(10, 20);

    从图中可以看到,我在方法体中是找不到所谓的 _ 变量的,这就神奇了,怎么做到的呢? 带着这个好奇心看看它的IL代码是个什么样子。

    .method private hidebysig static

    void Main (

    string[] args

    ) cil managed

    {

    //Method begins at RVA0x2048

    // Code size 45 (0x2d)

        .maxstack 3

        .entrypoint

        .locals init (

            [0] class [System.Runtime]System.Func`3<int32, int32, int32> func,

            [1] int32 result

        )

        IL_0000: nop

        IL_0001: ldsfld class [System.Runtime]System.Func`3<int32, int32, int32> ConsoleApp1.Program/'<>c'::'<>9__0_0'

    IL_0006:dup

    IL_0007:brtrue.s IL_0020

    IL_0009:pop

    IL_000a:ldsfldclassConsoleApp1.Program/'<>c'ConsoleApp1.Program/'<>c'::'<>9'

    IL_000f:ldftninstanceint32ConsoleApp1.Program/'<>c'::'b__0_0'(int32,int32)

    IL_0015:newobjinstancevoidclass[System.Runtime]System.Func`3::.ctor(object,nativeint)

    IL_001a:dup

    IL_001b:stsfldclass[System.Runtime]System.Func`3ConsoleApp1.Program/'<>c'::'<>9__0_0'

    IL_0020:stloc.0

    IL_0021:ldloc.0

    IL_0022:ldc.i4.s10

    IL_0024:ldc.i4.s20

    IL_0026:callvirtinstance!2class[System.Runtime]System.Func`3::Invoke(!0, !1)

    IL_002b:stloc.1

    IL_002c:ret

    } //endofmethodProgram::Main

    从上面的IL代码来看 匿名方法 变成了<>c类的<Main>b__0_0方法,完整签名:

    ConsoleApp1.Program/'<>c'::'<Main>b__0_0'(int32, int32),然后再找一下 <Main>b__0_0 方法的定义。

    .classnestedprivateautoansisealedserializablebeforefieldinit'<>c'

    extends[System.Runtime]System.Object

    .methodassemblyhidebysig

    instanceint32'b__0_0' (

    int32_,

    int32_

    )cilmanaged

        {

    //MethodbeginsatRVA0x2100

    //Codesize7 (0x7)

    .maxstack1

    .localsinit(

    [0]int32

            )

    IL_0000:nop

    IL_0001:ldc.i4.0

    IL_0002:stloc.0

    IL_0003:br.sIL_0005

    IL_0005:ldloc.0

    IL_0006:ret

    } //endofmethod'<>c'::'b__0_0'

    这说明什么呢? 说明两个参数是真实存在的,但编译器捣了鬼,做了语法上的限制,不让你访问所谓的 _。

    等等。。。有一个问题,IL中的方法签名怎么是这样的: <Main>b__0_0 (int32 _,int32 _), 大家应该知道方法签名中不可以出现重复的参数名,比如下面这样定义肯定是报错的。

    这说明什么? 说明这个语法糖不仅需要编译器支持,更需要底层的JIT支持,那怎么证明呢?我们用windbg去底层挖一挖。。。为了方便调试,修改如下:

    static void Main(string[] args)

    {

    Funcfunc=(_, _)=>

    {

    Console.WriteLine("进入方法体了!!!");

    Console.ReadLine();

    return0;

    };

    varresult =func(10, 20);

            }

    0:000> !clrstack-p

    OSThreadId: 0x52e8(0)

    0000007035F7E5C000007ffaff362655ConsoleApp1.Program+c.b__0_0(Int32, Int32)[C:\5\ConsoleApp1\ConsoleApp1\Program.cs@ 13]

    PARAMETERS:

    this(0x0000007035F7E600)= 0x000001968000cb48

    _(0x0000007035F7E608)= 0x000000000000000a

    _(0x0000007035F7E610)= 0x0000000000000014

    从图中可以看到,虽然都是 _ ,但在线程栈上是完完全全的两个栈地址。 0x0000007035F7E608 和 0x0000007035F7E610。

    总结

    总的来说,C#是越来越像函数式编程靠拢,越来越像Scala,就像Jquery的口号一样: Write less,do more。

    相关文章

      网友评论

          本文标题:C#9.0终于来了,有什么新特点?带上VS一起解读吧!

          本文链接:https://www.haomeiwen.com/subject/ocuatktx.html