避免 Value 属性 为可空值类型?
avoid Value property for nullable value types?
如果我有一个可为 null 的值类型,我总是必须使用它的值 属性,即使在我检查它是否为 null 之后也是如此。有解决办法吗?
public void Foo(SomeStruct? s)
{
if (s != null)
{
DoIt(s.Value.x + s.Value.y + s.Value.z);
}
}
显而易见的方法是定义一个新变量,这使得它影响的每个变量的代码都更长,而且我发现这会使代码更难阅读:
if (s != null)
{
var sv = s.Value;
DoIt(sv.x + sv.y + sv.z);
}
我想到的另一件事是模式匹配,但这有运行时类型检查的缺点:
if (s is SomeStruct sv)
{
DoIt(sv.x + sv.y + sv.z);
}
我是不是忽略了什么(除了我可能应该首先避免空变量这一事实)?
如果您可以使用 C# 8 - 您可以使用 属性 模式,它实际上变成了 HasValue
检查:
if(s is {} sv)
{
Console.WriteLine(sv);
}
会被编译器变成这样的(sharplab):
int num;
if (s.HasValue)
{
valueOrDefault = s.GetValueOrDefault();
num = 1;
}
else
{
num = 0;
}
if (num != 0)
{
Console.WriteLine(valueOrDefault);
}
if (s is SomeStruct sv)
不会 导致运行时类型检查。 这只是一个直接的 HasValue
检查
例如见this on Sharplab:
int? x=5;
if (x is int xv)
{
xv.ToString();
}
这编译为等同于:
int? x=5;
int xv;
if (x.HasValue)
{
xv = x.GetValueOrDefault();
xv.ToString();
}
请注意 GetValueOrDefault
已完全优化,不会检查 bool HasValue
标志。
实际IL如下
IL_0000: ldloca.s 0
IL_0002: ldc.i4.5
IL_0003: call instance void valuetype [System.Private.CoreLib]System.Nullable`1<int32>::.ctor(!0)
IL_0008: ldloca.s 0
IL_000a: call instance bool valuetype [System.Private.CoreLib]System.Nullable`1<int32>::get_HasValue()
IL_000f: brfalse.s IL_0021
IL_0011: ldloca.s 0
IL_0013: call instance !0 valuetype [System.Private.CoreLib]System.Nullable`1<int32>::GetValueOrDefault()
IL_0018: stloc.1
IL_0019: ldloca.s 1
IL_001b: call instance string [System.Private.CoreLib]System.Int32::ToString()
IL_0020: pop
如果我有一个可为 null 的值类型,我总是必须使用它的值 属性,即使在我检查它是否为 null 之后也是如此。有解决办法吗?
public void Foo(SomeStruct? s)
{
if (s != null)
{
DoIt(s.Value.x + s.Value.y + s.Value.z);
}
}
显而易见的方法是定义一个新变量,这使得它影响的每个变量的代码都更长,而且我发现这会使代码更难阅读:
if (s != null)
{
var sv = s.Value;
DoIt(sv.x + sv.y + sv.z);
}
我想到的另一件事是模式匹配,但这有运行时类型检查的缺点:
if (s is SomeStruct sv)
{
DoIt(sv.x + sv.y + sv.z);
}
我是不是忽略了什么(除了我可能应该首先避免空变量这一事实)?
如果您可以使用 C# 8 - 您可以使用 属性 模式,它实际上变成了 HasValue
检查:
if(s is {} sv)
{
Console.WriteLine(sv);
}
会被编译器变成这样的(sharplab):
int num;
if (s.HasValue)
{
valueOrDefault = s.GetValueOrDefault();
num = 1;
}
else
{
num = 0;
}
if (num != 0)
{
Console.WriteLine(valueOrDefault);
}
if (s is SomeStruct sv)
不会 导致运行时类型检查。 这只是一个直接的 HasValue
检查
例如见this on Sharplab:
int? x=5;
if (x is int xv)
{
xv.ToString();
}
这编译为等同于:
int? x=5;
int xv;
if (x.HasValue)
{
xv = x.GetValueOrDefault();
xv.ToString();
}
请注意 GetValueOrDefault
已完全优化,不会检查 bool HasValue
标志。
实际IL如下
IL_0000: ldloca.s 0
IL_0002: ldc.i4.5
IL_0003: call instance void valuetype [System.Private.CoreLib]System.Nullable`1<int32>::.ctor(!0)
IL_0008: ldloca.s 0
IL_000a: call instance bool valuetype [System.Private.CoreLib]System.Nullable`1<int32>::get_HasValue()
IL_000f: brfalse.s IL_0021
IL_0011: ldloca.s 0
IL_0013: call instance !0 valuetype [System.Private.CoreLib]System.Nullable`1<int32>::GetValueOrDefault()
IL_0018: stloc.1
IL_0019: ldloca.s 1
IL_001b: call instance string [System.Private.CoreLib]System.Int32::ToString()
IL_0020: pop