简体   繁体   English

如何识别泛型类型的可为空引用类型?

[英]How to identify a nullable reference type for generic type?

In C# 8 with nullable enabled, is there a way to identify a nullable reference type for generic type?在启用了可为空的 C# 8 中,有没有办法为泛型类型识别可为空的引用类型?

For nullable value type , there is a section dedicated to it.对于可空值类型,有一个专门的部分。 https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types#how-to-identify-a-nullable-value-type https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types#how-to-identify-a-nullable-value-type

We are trying to do optional null check according to the generic type我们正在尝试根据泛型类型进行可选的 null 检查

#nullable enable
public static Result<T> Create<T>(T value)
{
   if (!typeof(T).IsNullable() && value is null)
      throw new ArgumentNullException(nameof(value));

   // Do something
}

public static bool IsNullable(this Type type)
{
   // If type is SomeClass, return false
   // If type is SomeClass?, return true
   // If type is SomeEnum, return false
   // If type is SomeEnum?, return true
   // If type is string, return false
   // If type is string?, return true
   // If type is int, return false
   // If type is int?, return true
   // etc
}

So the following will throw ArgumentNullException when T is not nullable But allow value to be null with no exception when T is nullable, eg因此,以下将在T不可为空时抛出ArgumentNullException但是当T可以为空时,允许值为 null 没有异常,例如

Create<Anything>(null); // throw ArgumentNullException

Create<Anything?>(null); // No excception

In C# 8 with nullable enabled, is there a way to identify a nullable reference type for generic type?在启用了可为空的 C# 8 中,有没有办法为泛型类型识别可为空的引用类型?

In C# 8 there is NO way to check if a type parameter passed to a generic method is a nullable reference type or not.C# 8中,无法检查传递给泛型方法的类型参数是否为可为空的引用类型。

The problem is that any nullable reference type T?问题是任何可为空的引用类型T? is represented by the same type T ( but with a compiler-generated attribute annotating it ), as opposed to nullable value type T?由相同的类型T表示( 但使用编译器生成的属性对其进行注释),而不是可空值类型T? that is represented by the actual .NET type Nullable<T> .这由实际的 .NET 类型Nullable<T>表示。

When compiler generates code that invokes a generic method F<T> , where T can be either nullable reference type or not, an information if T is nullable refence type is lost.当编译器生成调用泛型方法F<T>的代码时,其中T可以是可为空的引用类型,也可以不是,如果T是可为空的引用类型的信息会丢失。 Lets consider the next sample method:让我们考虑下一个示例方法:

public void F<T>(T value) { }

For the next invocations对于下一次调用

F<string>("123");
F<string?>("456");

compiler will generate the next IL code (I simplified it a bit):编译器将生成下一个IL代码(我简化了一点):

call    F<string>("123")
call    F<string>("456")

You can see that to the second method a type parameter string is passed instead of string?您可以看到第二个方法传递的是类型参数string而不是string? because the representation of the nullable reference type string?因为可空引用类型string? during the execution is the same type string .在执行期间是相同类型的string

Therefore during execution it is impossible to define if a type parameter passed to a generic method is a nullable reference type or not.因此,在执行期间,无法定义传递给泛型方法的类型参数是否为可为空的引用类型。


I think that for your case an optimal solution would be to pass a bool value that will indicate if a reference type is nullable or not.我认为对于您的情况,最佳解决方案是传递一个bool值,该值将指示引用类型是否可为空。 Here is a sample, how it can be implemented:这是一个示例,它是如何实现的:

public static Result<T> Create<T>(T value, bool isNullable = false)
{
    Type t = typeof(T);

    // If type "T" is a value type then we can check if it is nullable or not.
    if (t.IsValueType) 
    {
        if (Nullable.GetUnderlyingType(t) == null && value == null)
            throw new ArgumentNullException(nameof(value));
    }
    // If type "T" is a reference type then we cannot check if it is nullable or not.
    // In this case we rely on the value of the argument "isNullable".
    else
    {
        if (!isNullable && value == null)
            throw new ArgumentNullException(nameof(value));
    }

    ...
}

You can't use nullable in the constraint, but you can use it in the method signature.您不能在约束中使用 nullable,但可以在方法签名中使用它。 This effectively constraints it to be a nullable type.这有效地将其限制为可为空的类型。 Example:例子:

static Result<Nullable<T>> Create<T>(Nullable<T> value) where T  : struct
{
    //Do something
}

Note that you can use this side by side with your existing method, as an overload , which allows you to execute a different logic path if it's nullable versus if it is not.请注意,您可以将此与现有方法并排使用,作为重载,它允许您执行不同的逻辑路径,如果它可以为空,或者它不是。

static Result<Nullable<T>> Create<T>(Nullable<T> value) where T  : struct
{
    Log("It's nullable!");
    Foo(value);
}

public static Result<T> Create<T>(T value)
{
    Log("It's not nullable!");
    Foo(value);
}

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

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