如何识别泛型类型的可为空引用类型?
Posted
技术标签:
【中文标题】如何识别泛型类型的可为空引用类型?【英文标题】:How to identify a nullable reference type for generic type? 【发布时间】:2020-09-21 16:53:49 【问题描述】:在启用 nullable 的 C# 8 中,有没有办法为泛型类型识别 可为 null 的引用类型?
对于可为空的值类型,有一个专门的部分。 https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types#how-to-identify-a-nullable-value-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
所以当T
不可为空时,以下将抛出ArgumentNullException
但是当T
可以为空时,允许值为空,例如
Create<Anything>(null); // throw ArgumentNullException
Create<Anything?>(null); // No excception
【问题讨论】:
这能回答你的问题吗? How to use .NET reflection to check for nullable reference type你也可以看看nullable-metadta规范 @JasonYu 是否需要定义引用类型是否可以为空? @Iliar Turdushev 这就是我想做的。但约束只能像where T : notnull
那样工作。我希望Create<T>
方法根据T
是否可以为空来抛出ArgumentNullException
【参考方案1】:
在启用 nullable 的 C# 8 中,有没有办法识别 nullable 泛型类型的引用类型?
在C# 8
中,无法检查传递给泛型方法的类型参数是否为可为空的引用类型。
问题是任何可空引用类型T?
都由相同的类型T
(but with a compiler-generated attribute annotating it) 表示,而不是由实际.NET 类型Nullable<T>
表示的可空值类型T?
.
当编译器生成调用泛型方法F<T>
的代码时,T
可以是可为空的引用类型,也可以不是,如果T
是可为空的引用类型的信息会丢失。让我们考虑下一个示例方法:
public void F<T>(T value)
用于下一次调用
F<string>("123");
F<string?>("456");
编译器将生成下一个IL
代码(我简化了一点):
call F<string>("123")
call F<string>("456")
你可以看到第二个方法传递了一个类型参数string
而不是string?
,因为在执行期间可空引用类型string?
的表示是相同的类型string
。
因此,在执行期间,无法定义传递给泛型方法的类型参数是否为可为空的引用类型。
我认为对于您的情况,最佳解决方案是传递一个 bool
值,该值将指示引用类型是否可为空。这是一个示例,它是如何实现的:
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));
...
【讨论】:
【参考方案2】:你不能在约束中使用 nullable,但是你可以在方法签名中使用它。这有效地将其限制为可为空的类型。示例:
static Result<Nullable<T>> Create<T>(Nullable<T> value) where T : struct
//Do something
请注意,您可以将此方法与现有方法一起使用,作为 重载,它允许您执行不同的逻辑路径,如果它可以为空,而不是如果它不是。
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);
【讨论】:
有notnull
约束,如Result<T> Create<T>(T value) where T : notnull
,我正在尝试使用新的可空引用类型而不是Nullable<T>
这仅考虑了struct
。在我们的例子中,泛型类型可以是任何类或结构。 T
可能是SomeClass
或SomeClass?
或SomeEnum
或SomeEnum?
或int?
等
但这将如何处理可为空的引用类型,例如可能为空的字符串?以上是关于如何识别泛型类型的可为空引用类型?的主要内容,如果未能解决你的问题,请参考以下文章