c# - 泛型和可空(类与结构)

标签 c# .net-core nullable .net-core-3.0 c#-8.0

编辑:在给我模式等选项之前,请参阅下面我对 C#8.0 中 Null 的立场的更新


原始问题

我正在尝试将我的基础库升级为“启用空”,也就是使用 C# 8.0 <Nullable>enable</Nullable>旗帜。

在尝试使用抽象和特定泛型时,我遇到了一些问题。考虑以下代码片段,它接受 Action。并将其转换为 Func<TResult> .这是pre-nullable-enable:

public static Func<TResult> ToFunc<TResult>(this Action action)
        => () => { action(); return default; }
;

但是 post-nullable-enable 我似乎很挣扎,因为我不能让 TResult 可以为空(或 TResult? ),因为机智需要 where TResult: class 的约束或 where TResult: struct .我无法将这两个约束结合起来让编译器知道 TResult 可以是类或值类型。目前我觉得这很烦人 - 因为人们应该能够表达无论是类还是结构,它都可以为空(无论以前的 .NET 继承设计如何)。

所以,post-nullable-enable我似乎只有一个选择,那就是代码重复,例子如下:

public static Func<TResult?> ToFuncClass<TResult>(this Action action)
        where TResult : class
        => () => { action(); return null; }
;

public static Func<TResult?> ToFuncStruct<TResult>(this Action action)
        where TResult : struct
        => () => { action(); return null; }
;

代码重复以及随之而来的命名方案都让我很困扰。我可能误解了正确的用法,或者我可能遗漏了规范的另一个功能,但您将如何解决这个问题?


更新:事实上,我认为我宁愿坚持使用我自己的“空处理”实现,也不愿使用 C#8.0 的可空特性。作为一个“空”对象或充实的“选项/可能/无”-解决方案似乎可以更好地传达信息。我唯一担心的是它在插入语言发展培训新编码员和引入另一个方面不是很有帮助>第三方/非本地解决方案普遍问题我们都处理空值。 因为自己的 null 处理实现 非常棒,但是在每个代码库中出现不同,需要由社区维护,并且您有各种不同的风格。因此,如果语言完全强制执行它,并且标准上升,那将是非常有帮助和非常有益的。我希望这会是 - 显然不是,我理解。但我觉得这是一个错失的机会。

谢谢 伊夫

最佳答案

原因在Try out Nullable Reference Types中解释在 The issue with T? 部分.本质上,没有办法解决这个问题。

首先,什么是T当我们使用 T? ?它是可为空的还是不可为空的?

A natural definition of T? would mean, "any nullable type". However, this would imply that T would mean "any non-nullable type", and that is not true! It is possible to substitute a T with a nullable value type today (such as bool?).

其次,每种情况下使用的类型不同 - a string?仍然是string同时 int?Nullable<int> .在每种情况下生成的具体方法 是完全不同的。在一种情况下,您会得到一个

Func<string> ToFuncClass<string>(this Action action)

在另一个方面,你得到一个

Func<Nullable<int>> ToFuncStruct<int>(this Action)

Next, it’s important to note that a nullable reference type is not the same thing as a nullable value type. Nullable value types map to a concrete class type in .NET. So int? is actually Nullable. But for string?, it’s actually the same string but with a compiler-generated attribute annotating it. This is done for backwards compatibility. In other words, string? is kind of a "fake type", whereas int? is not.

文章的示例演示了这一点:

This distinction between nullable value types and nullable reference types comes up in a pattern such as this:

void M<T>(T? t) where T: notnull

This would mean that the parameter is the nullable version of T, and T is constrained to be notnull.

If T were a string, then the actual signature of M would be :

M<string>([NullableAttribute] T t)

but if T were an int, then M would be

M<int>(Nullable<int> t)

These two signatures are fundamentally different, and this difference is not reconcilable.

关于c# - 泛型和可空(类与结构),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58317700/

相关文章:

c# - 从内存而不是磁盘向 CompilerParameters ReferencedAssemblies 提供程序集?

c# - EF Core 多对多自连接

c# - SqlDataReader 对象的内联空检查

c# - 使用 Reactive Extensions 同时处理流时如何限制缓冲

c# - CosmosDb - 写入操作导致错误。错误=16500

c# - 任务计划程序中的 Oracle 错误

permissions - 将角色声明作为权限的推荐最佳实践

azure - .net core Azure Functions启动类未被调用

c# - C# 中泛型方法的 Nullable<T>?

c# - 如何检查泛型类型参数是否可为空?