Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 默认表达式_C#_Generics - Fatal编程技术网

C# 默认表达式

C# 默认表达式,c#,generics,C#,Generics,在C#规范中,首先说: 如果默认值表达式中的类型在运行时计算为 引用类型,则将结果转换为该类型。如果类型 在默认值中,表达式在运行时计算为值类型, 结果是值类型的默认值(§4.1.2) 因此,似乎默认表达式是在运行时计算的。。。但是 据说: 默认值表达式是常量表达式(§7.19),如果 类型是引用类型或已知为 参考类型(§10.1.5)。此外,默认值表达式是 常量表达式(如果类型是以下值类型之一): sbyte、byte、short、ushort、int、uint、long、ulong、char

在C#规范中,首先说:

如果默认值表达式中的类型在运行时计算为 引用类型,则将结果转换为该类型。如果类型 在默认值中,表达式在运行时计算为值类型, 结果是值类型的默认值(§4.1.2)

因此,似乎默认表达式是在运行时计算的。。。但是 据说:

默认值表达式是常量表达式(§7.19),如果 类型是引用类型或已知为 参考类型(§10.1.5)。此外,默认值表达式是 常量表达式(如果类型是以下值类型之一): sbyte、byte、short、ushort、int、uint、long、ulong、char、float、, double、decimal、bool或任何枚举类型

那么,如果只检查运行时类型,那么
default
如何成为常量表达式,从而计算编译时

例如,如果我写了如下内容:

J k = default(J);
其中,
J
是一个类型参数,只有在运行时,当我们提供参数类型时,我们才能知道
J
是引用类型还是值类型。
那么编译时会发生什么呢

它是在编译时计算的,因为
J
也是这样,您不在运行时提供参数类型,而是在编译时提供参数类型,因此如果您有一个类
foo
,其中包含一个方法栏,其中包含您在执行时提到的代码

foo<int> myfoo =new foo<int>(); // this is also evaluated at compile time
myfoo.bar(); // the compiler invokes the bar method of the foo<int> type and thus returns default(int)
foo myfoo=new foo();//这也会在编译时进行评估
myfoo.bar();//编译器调用foo类型的bar方法,从而返回默认值(int)

您只是看错了规范(我的重点):

  • 默认值表达式是常量表达式(§7.19),如果该类型是引用类型或已知为 参考类型
这意味着,如果(且仅当)类型或类型参数已知为引用类型(即,它具有
其中T:class
约束或
默认值(SomeClass)
),则表达式为常量。继续:

  • 此外,默认值表达式是常量表达式如果该类型是以下值类型之一:sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal、, bool或任何枚举类型
这意味着,出于某种原因,您正在使用
default(sbyte)
default(short)

例如,给出以下代码:

void Main()
{
    var x = default(byte);
    var y = default(M);
}

public struct M { }
排放的IL将为:

IL_0000:  nop         
IL_0001:  ldc.i4.0    
IL_0002:  stloc.0     // x
IL_0003:  ldloca.s    01 // y
IL_0005:  initobj     UserQuery.M
IL_000B:  ret  
其中对于
byte
编译器可以发出0,它必须为我们的
M
结构调用
initobj

如果默认值表达式中的类型在运行时计算为引用类型

如果类型在编译时的计算结果肯定是引用类型,或者肯定不是引用类型,那么它在运行时的计算结果可以在编译时确定

这适用于具有类型参数
T
的泛型方法(或泛型类的方法)中的
default(string)
default(int)
,但不适用于
default(T)
(除非约束方式意味着它只能是另一个)

因此,只能在运行时推导参考类型或非参考类型的质量

严格地说,它实际上可以在jit时间推导出来,这确实是可以做到的,包括不被编译的逻辑已知为死的代码,因此:

if (default(T) == null)
{
   // code for reference-type or Nullable<> types of T
}
else
{
  // code for non-nullable value types of T
}
if(默认值(T)==null)
{
//T的引用类型或可为空类型的代码
}
其他的
{
//T的不可为空值类型的代码
}

只有使用的分支将被编译为机器代码,并且在任何情况下都会跳过比较本身。

但是您所说的与之形成对比:“默认值表达式中的类型在运行时计算为引用类型”“。不,它不会,它只是指定默认值将返回的值(默认值的实现),它返回的不是什么类型,措辞模棱两可,而且更不清楚,因为您删除了if,但它只是说明在面对不同类型时默认值的行为,而不是它将返回什么类型(它基本上很简单地解释了,对于值类型,您得到默认值类型,对于引用类型,您得到null,这与确定您得到的类型无关,只与您得到的类型的值有关)嗯,听起来好像我偏离了问题的主题,将删除我的答案,编辑:实际上不会删除我的答案,尽管它不会回答问题,因为它确实回答了“只有在运行时,当我们提供参数类型时,我们才能知道J是引用类型还是值类型”假设是由OP做出的,不确定我是否应该删除它或将其重写为注释我是,我把这个问题理解为“既然我们在编译时不知道它,它怎么知道J的类型”而不是“它怎么可能是一个常量值”,我肯定不会通过声明foo将具有默认值(int)来回答这一部分,我确实回答了J将是什么,但不是默认值是否会在运行时或编译时执行工作(我也不知道)。我们如何才能只在运行时知道
J
,而在代码中有
default(J)
?因此,只有当编译器“知道”该类型是引用类型或值类型(byte、int等)时,我们才能推断默认值在编译时计算.Else默认评估运行时,这是在没有约束的情况下定义泛型的情况。