我遇到了 foreach 方法的奇怪行为。当我放下这段代码时:
var result = repository.Data.Where(<some_long_selector>).ToList();
result.ForEach(e =>
{
e.x = CalcX(e);
e.y = GetAllYs().FirstOrDefault(y => y.Id == e.x)
});
一切都好。
但是,当我尝试像这样使用自制的 elvis“运算符”(或实际上是“默认值运算符”)时:
var result = repository.Data.Where(<some_long_selector>).ToList();
result.ForEach(e =>
{
e.x = CalcX(e);
e.y = GetAllYs().FirstOrDefault(y => y.Id == e.x).Elvis(new Y("empty"));
});
这里Elvis
是
public static T Elvis<T>(this T? instance, T defaultValue)
{
if (instance == null) return defaultValue;
else return instance.Value;
}
我收到 ForEach 方法的“无效参数”错误(即某种类型错误)。这对我来说很意外。我了解可能的解决方法,但我只想知道这种情况如何发生以及为什么发生,以及在保留此(或稍作修改的)Elvis 扩展功能的同时纠正它的最省力的方法是什么?
PS 我是 Java 开发人员,需要在我们的团队开发替代品时支持一些遗留的 C# 代码。所以,对不起,如果我错过了一些明显的东西
Elvis 还必须将其通用参数限制为struct
或class
,如下所示:
public static T Elvis<T>(this T? instance, T defaultValue)
where T : class
{
...
}
要么
public static T Elvis<T>(this T? instance, T defaultValue)
where T : struct
{
...
}
这是因为直到最近,该语言还没有通用可空性的概念——只有结构可以显式地设置为可空性(因为无论您喜欢与否,类都是可空性的)。一个可为空的结构被Nullable<T>
编译器悄悄地包装在一个类型中,一切都很好。
这意味着在通用签名中使用可空运算符要求参数是一个结构体,因为它对类没有意义(直到最近)。因此需要显式结构约束才能使用运算符。
但是,现在我们也有可为空的引用类型,您会认为,允许可空运算符通常不受约束是有道理的 - 但由于旧的事物方式,这会导致某些地方出现混乱,因此语言团队说“不”(请参阅此处:https : //github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-11-25.md)
结果是,您必须有一个显式约束才能以这种方式使用可空运算符 - 您必须在适用于引用类型或结构类型的扩展方法之间进行选择,但不能同时使用两者(我认为...)
另一个有用的链接:https : //www.meziantou.net/csharp-8-nullable-reference-types.htm#generic-types
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句