CSharp新语法

起因

前一段时间在看.Net Core 3.0与.Net Core 2.0在性能测试对比,发现在3.0相对2.0有了很大的提升,在对比ConcurrentDictionary中与.NetFramework源码对比,发现本地函数这个相对新的语法.对于长期使用VS2008的我来说,这个语法是真的很新了. 

VS2019在更新到16.2.5(Windows版本),VS For Mac 最新版本也同步支持了,一个好的功能,根据类型导入命名空间(未引用dll的时候),这个功能在Java(Idea中)很早之前就有了。

本地函数(c# 7.0) ConcurrentDictionary(.Net Core 3.0)中的IsEmpty函数

public bool IsEmpty
{
    get
    {
        // Check if any buckets are non-empty, without acquiring any locks.
        // This fast path should generally suffice as collections are usually not empty.        // 第一次调用内部的本地函数,未加锁,验证不为真的时候
        if (!AreAllBucketsEmpty())
        {
            return false;
        }

        // We didn't see any buckets containing items, however we can't be sure
        // the collection was actually empty at any point in time as items may have been
        // added and removed while iterating over the buckets such that we never saw an
        // empty bucket, but there was always an item present in at least one bucket.
        int acquiredLocks = 0;
        try
        {                        // 加锁
            AcquireAllLocks(ref acquiredLocks);

            return AreAllBucketsEmpty();   // 再次调用本地函数
        }
        finally
        {
            // 释放锁
            ReleaseLocks(0, acquiredLocks);
        }
        //在函数内部,定义本地函数,可以在当前函数内部,进行多次调用
        bool AreAllBucketsEmpty()
        {
            int[] countPerLock = _tables._countPerLock;

            for (int i = 0; i < countPerLock.Length; i++)
            {
                if (countPerLock[i] != 0)
                {
                    return false;
                }
            }

            return true;
        }
    }
}

在 Performance Improvements in .NET Core 3.0 一文中,看到ConcurrentDictionary<TKey, TValue>,和 ConcurrentQueue<T> 中的IsEmpty在.Net Core 2.1 和 .Net Core 3.0性能对比相差是很大的。在看过源码中,可以看到主要是在锁处理,第一次判断字典内元素是否为空是没有加锁的,当然是在CLR应该也是做了不少优化。

数字文本语法改进(7.0),只是语法糖

//数字文本改进
//下面这样,更容易使用和读取
int num = 100_000_000;   //数字中的下划线,在编译的时候,由编译器自动剔除
Console.WriteLine($"num={num}");
IL_0000: nop
IL_0001: ldc.i4 100000000   //查看编译之后il代码,可以看到数字中的下划线已经在编译的时候自动剔除了
IL_0006: stloc.0
IL_0007: ldstr "num={0}"
IL_000c: ldloc.0
IL_000d: box [mscorlib]System.Int32
IL_0012: call string [mscorlib]System.String::Format(string,  object)
IL_0017: call void [System.Console]System.Console::WriteLine(string)

VS2019自动导入类型所在的dll

在.Net Core中使用Span 一文中,讲到UnSafe类型进行指针交互,当时不知道UnSafe在其他dll中,由于没有添加dll,所以无法使用。
VS2019根据类型,自动导入类型所在的程序集(dll)文件

更好用的using(c# 8.0)

//using { xxx} 可以去掉大括号{} 
using FileStream stream = new FileStream("hello.txt", FileMode.OpenOrCreate);
string str = "0x5A4D"; //测试数据
byte[] buffer = Encoding.UTF8.GetBytes(str);
stream.Write(buffer, 0, buffer.Length);

List<int> list = new List<int>();
for (int i = 0; i < 100; i++)
{
    list.Add(i + 1);
}
Console.WriteLine(list[9]);
Console.WriteLine("Hello World!");

//多次使用using
using var con = new SqlConnection("");

上边的代码,查看编译成后的代码,大括号(作用域)自动加上

using (FileStream fileStream = new FileStream("hello.txt", FileMode.OpenOrCreate))
{
    byte[] bytes = Encoding.UTF8.GetBytes("0x5A4D");
    fileStream.Write(bytes, 0, (int)bytes.Length);
    List<int> nums = new List<int>();
    for (int i = 0; i < 100; i = checked(i + 1))
    {
        nums.Add(checked(i + 1));
    }
    Console.WriteLine(nums[9]);
    Console.WriteLine("Hello World!");
    using (SqlConnection sqlConnection = new SqlConnection(""))
    {
    }
}

可以通过编译后的代码,发现using 新的用法也只是个语法糖.

秋风 2019-09-11