我有一个可为空的 c# 10 .net 6 项目,其扩展方法为
ThrowIfNull
using System;
using System.Runtime.CompilerServices;
#nullable enable
public static class NullExtensions
{
public static T ThrowIfNull<T>(
this T? argument,
string? message = default,
[CallerArgumentExpression("argument")] string? paramName = default
)
{
if (argument is null)
{
throw new ArgumentNullException(paramName, message);
}
else
{
return argument;
}
}
}
扩展方法隐式地将
string?
转换为 string
但它不适用于其他基本类型,例如 int?
或 bool?
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
string? foo = "foo";
string nonNullableFoo = foo.ThrowIfNull(); // success from "string?" to "string"
Console.WriteLine(nonNullableFoo);
bool? baz = true;
bool nonNullableBaz = baz.ThrowIfNull(); // success from "string?" to "string"
Console.WriteLine(nonNullableFoo);
int? bar = 2;
int nonNullableBar = bar.ThrowIfNull(); // error: Cannot implicitly convert type 'int?' to 'int'
Console.WriteLine(nonNullableBar);
}
}
如何使扩展隐式转换
int?
和 bool?
?
这是完整的 dotnet 小提琴 https://dotnetfiddle.net/LiQ8NL
您可以通过为不可空引用类型提供一种扩展方法并为非托管(例如 int、bool 等)类型提供另一种扩展方法来实现您的目标。请注意,非托管类型需要强制转换。
public static class NullExtensions
{
public static T ThrowIfNull<T>(
this T? argument,
string? message = default,
[CallerArgumentExpression("argument")] string? paramName = default
) where T : notnull
{
if (argument is null)
{
throw new ArgumentNullException(paramName, message);
}
else
{
return argument;
}
}
public static T ThrowIfNull<T>(
this T? argument,
string? message = default,
[CallerArgumentExpression("argument")] string? paramName = default
) where T : unmanaged
{
if (argument is null)
{
throw new ArgumentNullException(paramName, message);
}
else
{
return (T)argument;
}
}
}
像这样使用:
int? foo = 42;
int bar = foo.ThrowIfNull();
Console.WriteLine(bar);
string? baz = "Hello";
string quus = baz.ThrowIfNull();
Console.WriteLine(quus);
// Comment out either this
baz = null;
quus = baz.ThrowIfNull();
// Or this
foo = null;
bar = foo.ThrowIfNull();
??
要将可为空值分配给非空变量,请考虑以下代码:
int? value = 28;
int result = value ?? -1;
Console.WriteLine($"The result is {result}");
The result is 28
int? value = null;
int result = value ?? -1;
Console.WriteLine($"The result is {result}");
The result is -1
按如下方式重新排列代码。因此
bool?
您可以隐式使用该类型:
int? bar = 2;
int nonNullableBar = bar ?? -1;
Console.WriteLine(nonNullableBar);
bool? baz = true;
bool nonNullableBaz = false;
if (baz == true){
nonNullableBaz = true;
}
else if(baz == false){
nonNullableBaz = false;
}
else {
/* Something */
}
在 MS dotnet 文档中找到了一种可能的选项 https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters
约束“where T : struct”类型参数必须是不可为 null 的值类型
另外根据此答案https://stackoverflow.com/a/8745492/2877168,不可能使此功能适用于
string?
和所有其他值类型。所以唯一的方法是定义两个扩展方法。这是适用于 string?
和 int?
、bool?
等 的更新版本
public static class NullExtensions
{
public static T ThrowIfNull<T>(this T? argument, string? message = default, [CallerArgumentExpression("argument")] string? paramName = default)
where T : struct
{
if (argument is null)
throw new ArgumentNullException(paramName, message);
return (T)argument;
}
public static string ThrowIfNull(this string? argument, string? message = default, [CallerArgumentExpression("argument")] string? paramName = default)
{
if (argument is null)
throw new ArgumentNullException(paramName, message);
return argument;
}
}
其工作版本位于 https://dotnetfiddle.net/uBX1w6
如果没有成功的非空赋值就无法继续,您可以使用以下语句:
int result = getNullableIntResult() ?? throw new Exception("Invalid Result");