如何在同一个方法中处理非空类和值类型?

5
请注意,这个问题的前提是一个可空上下文,这是NET 6的默认设置。
我想编写一个方法Read,它接受一个非空类型(即结构体或类),并输出该结构体或类的可空版本。类似于这样(显然它不只是返回默认值,但没有必要复杂化这个问题):
public static T? Read<T>()
{
    return default; //should return null
}

这个示例方法应该返回null,确实对于类、可为空的类和可为空的值类型,它也是返回null,但对于值类型则不是。
Console.WriteLine(null == Read<string>()); //true
Console.WriteLine(null == Read<string?>()); //true
Console.WriteLine(null == Read<int>()); //false
Console.WriteLine(null == Read<int?>()); //true

我希望有一种方法,可以对所有这些情况都返回 true。我已经尝试了许多在 T 上的 constraints 限制。我感觉 notnull 限制应该可以工作,但它并没有。
我可以只创建两个方法,一个受限于 struct(即值类型),另一个受限于 class(即非空引用类型)。以下方法可行:
public static T? ReadValue<T>()  where T: struct
{
    return null; //does return null
}

public static T? ReadRef<T>()  where T: class
{
    return null; //does return null
}

但是,正如您所看到的,这两种方法如果没有约束和不同的名称将完全相同(需要不同的名称是因为它们具有相同的签名)。因此,我觉得必须为此创建两种不同的方法似乎有些愚蠢。

背景:我知道这种情况的笨拙部分是由于可空值类型在幕后由Nullable<T>表示,而可空类只是由编译器跟踪。我只想知道是否有一种避免这种情况的方法。


2
“我只是想知道是否有避免这种情况的方法。” - 实际上并没有。 - Dai
4
我对扩展方法所做的事情是将它们放在不同的类中,以避免签名冲突,让编译器能够选择正确的方法。如果您可以接受在方法前加上不同的类名称作为前缀,这些方法就不再是扩展方法了,您也可以达到同样的效果。但这看起来与给它们命名不同的方法有相同的缺点。 - madreflection
@madreflection 这是一个相当聪明的想法,我可能会尝试一下。 - Tester Bill
1个回答

0

据我所知,这是不可能的,原因如下:

  1. 对于没有显式提供参数的调用的重载解析(对于显式提供泛型类型参数的调用,您可以使用类似于this question答案中指定的方法 - 请自行查看yourself)- 请参阅Jon Skeet的精彩博客文章。

  2. 当泛型类型参数T既不受限于class也不受限于struct时,编译器将针对值类型和引用类型以不同方式处理T?,对于值类型,T?将等于T(请参见this答案)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接