【发布时间】:2019-10-10 07:34:29
【问题描述】:
编辑: 在给我模式等选项之前,请参阅下面关于我在 C#8.0 中对 Null 的立场的更新
原始问题
我正在尝试将我的基础库升级为“启用空值”,也就是使用 C# 8.0 <Nullable>enable</Nullable> 标志。
在尝试使用抽象和特定泛型时,我遇到了一些问题。考虑以下代码 sn-p,它接收 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; }
;
代码重复以及随之而来的命名方案都让我很困扰。我可能误解了正确的用法,或者我错过了规范的另一个功能,但是您将如何解决这个问题?
更新:事实上,我认为我宁愿坚持自己的“null-handling”实现,也不愿使用 C#8.0 的可为空功能。作为“Void” 对象或充实的“Option/Maybe/None”-解决方案 似乎可以更好地传达事物。我唯一担心的是它在推动语言发展、培训新的编码员和引入另一个方面并不是很有帮助 >第三方/非本地解决方案到我们都有处理空的通用问题。 因为 自己的 null 处理实现 很棒,但是在每个代码库中不同,需要由社区维护,并且您有各种不同的风格。因此,如果语言完全执行它,并且如果 标准 上升,那将是非常有帮助和巨大的好处。我希望这是 - 显然不是,我理解。但我觉得这是一个错失的机会。
谢谢 伊夫
【问题讨论】:
-
没有重复。每种情况下的类型完全不同,这就是为什么这不被视为方法重载的原因。
-
编译器必须为可空结构和可空引用类型发出非常不同的代码。这就是为什么你不能表达“可以为空,不管是什么风格”
-
@Damien_The_Unbeliever 非常清楚我理解这种行为,但是在代码库中看到这一点相当笨拙,你曾经有效地用一种方法为每个案例并完成它。想象一下这对每个人来说都是通用方法,我觉得这被忽略了——即使底层类型(值/引用)不同,我想表达的行为在两种情况下显然是相同的。现在,当在一个类型上调用该方法时,我不能只调用 ToFunc,而是必须检查我将返回的结果类型(甚至在这里没有意义),然后选择 ToFuncX 或 To FuncY。
-
@YvesSchelpe 您想解决的真正问题是什么?函数式语言不会从方法返回
null,它们返回unit或void类型。你也可以这样做。System.Threading.Channels包含一个VoidResult类型,因为这个原因。 -
编译器可以完成这项工作,只要付出足够的努力。传统上,C# 的设计方式是使用一个特性所获得的成本是预先确定的(因此没有编译器魔法会产生大量开销),但该原则早已采用迭代器方法之类的方式,异步状态机和闭包和 lambda 的整个机器。更相关的原因是“没有办法在不破坏现有代码的情况下实现这一点”。如果在此功能之前没有
Nullable<T>,它本来可以完成的,但是现在已经是这样了,没有骰子。
标签: c# .net-core nullable .net-core-3.0 c#-8.0