简体   繁体   English

如何将可空类型隐式转换为不可空类型

[英]How to implicitly convert nullable type to non-nullable type

I have a nullable c# 10 .net 6 project with an extension method to ThrowIfNull我有一个可以为空的 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;
        }
    }
}

The extension method implicitly converts string?扩展方法隐式转换string? to string but it does not work for other primitive types like int?string ,但它不适用于其他原始类型,如int? or bool?还是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);
    }
}

How do I make the extension implicitly convert int?如何使扩展隐式转换int? and bool?bool? ? ?

Here is the full dotnet fiddle https://dotnetfiddle.net/LiQ8NL这是完整的 dotnet fiddle https://dotnetfiddle.net/LiQ8NL

You can achieve your goal by providing one extension method for non-nullable reference types and another for unmanaged (eg int, bool, ...) types.您可以通过为不可为空的引用类型提供一种扩展方法和为非托管(例如 int、bool、...)类型提供另一种扩展方法来实现您的目标。 Note that unmanaged types require a cast.请注意,非托管类型需要强制转换。

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

Use like this:像这样使用:

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();

1. Using the null-coalescing Operator ?? 1. 使用空合并运算符??

To assign a nullable value to a non-null variable, consider the following code:要将可空值分配给非空变量,请考虑以下代码:

int? value = 28;
int result = value ?? -1;
Console.WriteLine($"The result is {result}");
  • Output: The result is 28 Output: The result is 28
int? value = null;
int result = value ?? -1;
Console.WriteLine($"The result is {result}");
  • Output: The result is -1 Output: The result is -1

2. Editing The Code 2. 编辑代码

Rearrange the code as follows.重新排列代码如下。 Therefore bool?因此bool? You can use the type implicitly:您可以隐式使用该类型:

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 */
}

3. Resources 3. 资源

Found one possible option in MS dotnet docs https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters在 MS dotnet docs https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters中找到了一个可能的选项

Constraint "where T: struct" The type argument must be a non-nullable value type约束 "where T: struct" 类型参数必须是不可为空的值类型

Also according to this answer https://stackoverflow.com/a/8745492/2877168 it is not possible to make this work for string?同样根据这个答案https://stackoverflow.com/a/8745492/2877168不可能使这个工作为string? and all other value types.和所有其他值类型。 So only way is to define two extension methods.所以唯一的办法就是定义两个扩展方法。 Here is the updated version that works for string?这是适用于string? and int?int? , bool? bool? etc ETC

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

A working version of this is at https://dotnetfiddle.net/uBX1w6其工作版本位于https://dotnetfiddle.net/uBX1w6

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM