C# 11加入检查参数是否为空语法糖

起因

在C# 11中,加入了新的语法糖,在C#加入越来越多的语法,当编程语言加入太多的语法,会导致阅读代码时有些晦涩,不易读,刚开始不知道这个语法是要做什么,这个时候就要去官方文档,看看这个语法的功能是要做什么.

最早看到这个检查参数是否为空的语法是从这几个issue:
  1. Initial roll out of !! (#64720)
  2. Second round of changing null checks to !! (#65108)
  3. Add/use ArgumentException.ThrowIfNullOrEmpty (#64357)
目前新语法在检查参数为空,只能用在方法内的参数和构造方法的参数,对于方法内的参数使用ref和out修饰都是不可以的.

在普通方法,使用新语法校验参数是否为空

public bool Test1(string name)
{
    if (name == null)
    {
        throw new ArgumentNullException(nameof(name));
    }

    //等同于上方 if(name == null) { throw new ArgumentNullException("name");)
    //这种方式可以用在检查属性是否为空
    ArgumentNullException.ThrowIfNull(nameof(name));

    return true;
}

public bool Test2(string name!!)  //新语法, 在参数名加!! 
{
    return true;
}

要在项目工程文件,指定C#语言版本.

因为C# 11现在还没有发布正式版,所以要在项目工程文件指定语言版本为preview

<PropertyGroup>
	<OutputType>Exe</OutputType>
	<!--指定.Net版本-->
	<TargetFramework>net7.0</TargetFramework>
	<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
	<!--指定c#语言版本为与蓝本(preview)-->
	<LangVersion>preview</LangVersion>
</PropertyGroup>

在构造方法中检查参数是否为空

public class CheckParameterNull
{
    public string Address { get; }
    public CheckParameterNull(string address!!) //在构造方法,使用新语法检查参数是否
    {
        Address = address;
    }

    public bool Test1(string name)
    {
        if (name == null)
        {
            throw new ArgumentNullException(nameof(name));
        }

        //等同于上方 if(name == null) { throw new ArgumentNullException("name");)
        //这种方式可以用在检查属性是否为空
        ArgumentNullException.ThrowIfNull(nameof(name));

        return true;
    }

    public bool Test2(string name!!)  //新语法, 在参数名加!! 
    {
        return true;
    }
}

使用反编译工具 ILSpy 查看编译后的代码:

public class CheckParameterNull
{
	public string Address { get; }

	public CheckParameterNull(string address)
	{
        //编译器在编译时,会在程序集生成一个隐藏类PrivateImplementationDetails
		<PrivateImplementationDetails>.ThrowIfNull(address, "address");
		base..ctor();
		Address = address;
	}

	public bool Test1(string name)
	{
		if (name == null)
		{
			throw new ArgumentNullException("name");
		}
		ArgumentNullException.ThrowIfNull("name", "nameof(name)");
		return true;
	}

	public bool Test2(string name)
	{
		<PrivateImplementationDetails>.ThrowIfNull(name, "name");
		return true;
	}
}

编译器在编译时,会生成一个隐藏类PrivateImplementationDetails

[CompilerGenerated]
internal sealed class <PrivateImplementationDetails>
{
	internal static void Throw(string paramName)
	{
        //最终还是调用创建一个ArgumentNullException
		throw new ArgumentNullException(paramName);
	}

	internal static void ThrowIfNull(object argument, string paramName)
	{
		if (argument == null)
		{
			Throw(paramName);
		}
	}
}

对于这个新的语法糖,我是支持的,因为这个语法糖是可以提高一些生产力(这一点不是很多),但可以减少代码量,让项目的代码量不至于越来越膨胀.

这个看#65108这个issue:

在.Net核心库已经开始使用检查参数操作符

通过这个issue,这个语法是可以减少代码量的.

检查参数为空这个语法,已经在.Net底层核心库使用了


秋风 2022-02-18