Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/visual-studio-code/3.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# 如果T是int,拳击会在这里发生吗?_C#_Boxing - Fatal编程技术网

C# 如果T是int,拳击会在这里发生吗?

C# 如果T是int,拳击会在这里发生吗?,c#,boxing,C#,Boxing,所以问题是,如果T是int32,这里会有装箱还是编译器会选择不装箱的int32 Equals?对原始问题和Rango的基本正确答案的评论中有一些混乱,所以我想我应该澄清一下 首先,请注意泛型如何在C中工作。泛型不是模板 在C语言中,泛型由C编译器编译一次为泛型IL,然后由jitter将该IL重新编译为特殊形式。例如,如果我们有一个方法MT t,那么C编译器会将该方法及其主体编译一次,然后编译成IL 当抖动出现时,对M、M或M的调用将触发一次编译;jitter非常聪明,它可以将主体编译成一种无论类

所以问题是,如果T是int32,这里会有装箱还是编译器会选择不装箱的int32 Equals?

对原始问题和Rango的基本正确答案的评论中有一些混乱,所以我想我应该澄清一下

首先,请注意泛型如何在C中工作。泛型不是模板

在C语言中,泛型由C编译器编译一次为泛型IL,然后由jitter将该IL重新编译为特殊形式。例如,如果我们有一个方法MT t,那么C编译器会将该方法及其主体编译一次,然后编译成IL

当抖动出现时,对M、M或M的调用将触发一次编译;jitter非常聪明,它可以将主体编译成一种无论类型参数是什么都可以工作的形式,前提是类型参数是引用类型。但是M和M将各自编译到它们自己的汇编代码体中

请注意,抖动不知道C的规则,C不知道过载分辨率。当C编译器生成IL时,已经为每个方法调用选择了确切的方法。因此,如果你有:

public static bool Equal<T>(T value, T match) {
           return Equals(value, match);
       }
若T被证明是int,那个么两个int都被装箱到object

让我再次强调这一点。当我们到达抖动时,我们已经知道将调用哪个X;这个决定是在C编译时做出的。C编译器的原因是我有两个T,我不知道它们可以转换为int,所以我必须选择对象版本

这与C++模板代码相反,它重新编译每个模板实例化的代码,并重新执行过载解析。 这就回答了最初提出的问题

现在让我们进入奇怪的细节

当jit编译M时,是否允许jitter注意到M调用Xobject,object,然后调用object.Equalsobject,object(已知它比较两个装箱整数是否相等),并直接生成代码以比较两个整数的非装箱形式

是的,允许抖动执行该优化

它在实践中是否执行了这种优化

据我所知不是这样。抖动确实执行了一些内联优化,但据我所知,它不执行任何高级的内联

是否存在抖动在实践中消除拳击的情况

对!

你能举几个例子吗

当然可以。考虑下面的恐怖代码:

当我们这样做时:

struct S 
{
  public int x;
  public void M()
  {
      this.x += 1;
  }
}
会发生什么?这在值类型中相当于ref S类型的参数。所以我们将ref传递给S,传递给M,依此类推

现在考虑以下内容:

S s = whatever;
s.M();
现在假设我们这样做:

interface I
{
  void M();
}
struct S : I { /* body as before */ }
会发生什么

将s转换为I是一种装箱转换,因此我们分配一个箱子,使箱子实现I,并在箱子中复制s。 调用i.M将盒子作为接收器传递给盒子中的i的实现。然后,它将引用框中s的副本,并将该引用作为this传递给M。 好了,现在有一点会把你搞糊涂的

S s = whatever;
I i = s;
i.M();

好的,现在你知道U的唯一可能的类型是int,所以t应该可以赋值给U,U应该可以赋值给t,对吗?但是CLR验证器并不是这样看的,然后您可能会遇到这样的情况:编译器必须生成代码,导致int被装箱到object,然后取消装箱到U,即int,因此往返是没有意义的

这里有什么外卖

不要改变值类型。 泛型不是模板。重载解析只发生一次。 抖动很难消除泛型中的装箱,但是如果一个T被转换成object,那么这个T就真的,真的被转换成object了。
对原始问题和兰戈基本正确答案的评论有些混乱,所以我想我应该澄清一下

首先,请注意泛型如何在C中工作。泛型不是模板

在C语言中,泛型由C编译器编译一次为泛型IL,然后由jitter将该IL重新编译为特殊形式。例如,如果我们有一个方法MT t,那么C编译器会将该方法及其主体编译一次,然后编译成IL

当抖动出现时,对M、M或M的调用将触发一次编译;jitter非常聪明,它可以将主体编译成一种无论类型参数是什么都可以工作的形式,前提是类型参数是引用类型。但是M和M将各自编译到它们自己的汇编代码体中

请注意,抖动不知道C的规则,C不知道过载分辨率。当C编译器生成IL时,已经为每个方法调用选择了确切的方法。因此,如果你有:

public static bool Equal<T>(T value, T match) {
           return Equals(value, match);
       }
若T被证明是int,那个么两个int都被装箱到object

让我再次强调这一点。到 当我们到达抖动时,我们已经知道将调用哪个X;这个决定是在C编译时做出的。C编译器的原因是我有两个T,我不知道它们可以转换为int,所以我必须选择对象版本

这与C++模板代码相反,它重新编译每个模板实例化的代码,并重新执行过载解析。 这就回答了最初提出的问题

现在让我们进入奇怪的细节

当jit编译M时,是否允许jitter注意到M调用Xobject,object,然后调用object.Equalsobject,object(已知它比较两个装箱整数是否相等),并直接生成代码以比较两个整数的非装箱形式

是的,允许抖动执行该优化

它在实践中是否执行了这种优化

据我所知不是这样。抖动确实执行了一些内联优化,但据我所知,它不执行任何高级的内联

是否存在抖动在实践中消除拳击的情况

对!

你能举几个例子吗

当然可以。考虑下面的恐怖代码:

当我们这样做时:

struct S 
{
  public int x;
  public void M()
  {
      this.x += 1;
  }
}
会发生什么?这在值类型中相当于ref S类型的参数。所以我们将ref传递给S,传递给M,依此类推

现在考虑以下内容:

S s = whatever;
s.M();
现在假设我们这样做:

interface I
{
  void M();
}
struct S : I { /* body as before */ }
会发生什么

将s转换为I是一种装箱转换,因此我们分配一个箱子,使箱子实现I,并在箱子中复制s。 调用i.M将盒子作为接收器传递给盒子中的i的实现。然后,它将引用框中s的副本,并将该引用作为this传递给M。 好了,现在有一点会把你搞糊涂的

S s = whatever;
I i = s;
i.M();

好的,现在你知道U的唯一可能的类型是int,所以t应该可以赋值给U,U应该可以赋值给t,对吗?但是CLR验证器并不是这样看的,然后您可能会遇到这样的情况:编译器必须生成代码,导致int被装箱到object,然后取消装箱到U,即int,因此往返是没有意义的

这里有什么外卖

不要改变值类型。 泛型不是模板。重载解析只发生一次。 抖动很难消除泛型中的装箱,但是如果一个T被转换成object,那么这个T就真的,真的被转换成object了。
@兰戈:那么会有拳击比赛?为什么要回答不同的问题?=@Lewsterin-对象的签名是bool Equalsobject arg1;这与上面定义的方法或代码调用的方法(恰好是它自己)不同。简短的回答是:重载解析将选择公共静态bool等于object objA,object objB;参数将是整数。因此它们必须装箱,因为int到object是装箱转换。@EricLippert感谢Eric;即使使用返回值.Equalsmatch,装箱也始终会发生,因为并没有约束,所以假定为对象。如果在T:IEquatable处设置一个约束,那么就可以避免装箱。@Rango,那么会有装箱吗?为什么要回答不同的问题?=@Lewsterin-对象的签名是bool Equalsobject arg1;这与上面定义的方法或代码调用的方法(恰好是它自己)不同。简短的回答是:重载解析将选择公共静态bool等于object objA,object objB;参数将是整数。因此它们必须装箱,因为int到object是装箱转换。@EricLippert感谢Eric;即使使用返回值.Equalsmatch,装箱也始终会发生,因为并没有约束,所以假定为对象。如果您在T:IEquatable处设置约束,则可以避免装箱。
class C<T>
{
  public virtual void M<U>(T t, U u) where U : T { }
}
class D : C<int>
{
  public override void M<U>(int t, U u)
  {