public static bool Equal<T>(T value, T match) {
return Equals(value, match);
}
所以问题是,如果T是int32,那么这里是å¦å°†è£…箱,å¦åˆ™ç¼–译器将选择ä¸è£…箱的int32ç‰äºŽï¼Ÿ
ç”案 0 :(得分:6)
对原始问题和Rango(基本æ£ç¡®ï¼‰çš„回ç”在评论ä¸æœ‰äº›æ··ä¹±ï¼Œæ‰€ä»¥æˆ‘想我将其清除。
首先,有关泛型在C#ä¸çš„工作方å¼çš„说明。泛型ä¸æ˜¯æ¨¡æ¿ï¼
在C#ä¸ï¼Œæ³›åž‹ä¸€æ¬¡ç”±C#编译器编译为泛型IL,然åŽé€šè¿‡æŠ–动将ILé‡æ–°ç¼–译为特殊形å¼ã€‚例如,如果我们有一个方法M<T>(T t)
,那么C#编译器将将该方法åŠå…¶ä¸»ä½“一次编译为IL。
当出现抖动时,对M<string>
,M<object>
或M<IEnumerable>
的调用将触å‘一个精确的编译;抖动éžå¸¸èªæ˜Žï¼Œå¹¶ä¸”åªè¦ç±»åž‹å®žå‚是引用类型,它就å¯ä»¥å°†ä¸»ä½“编译æˆå¯ä»¥å·¥ä½œçš„å½¢å¼ï¼Œè€Œä¸ç®¡ç±»åž‹å®žå‚是什么。但是M<int>
å’ŒM<double>
都将被编译æˆè‡ªå·±çš„汇编代ç 主体。
请注æ„,抖动ä¸çŸ¥é“C#的规则,并且C#å¯ä»¥è¿›è¡Œè¿‡è½½è§£æžã€‚到C#编译器生æˆIL时,已ç»ä¸ºæ¯ä¸ªæ–¹æ³•è°ƒç”¨é€‰æ‹©äº†ç¡®åˆ‡çš„æ–¹æ³•ã€‚å› æ¤ï¼Œå¦‚果您有:
static bool X(object a, object b) => object.Equals(a, b);
static bool X(int a, int b) => a == b;
static bool M<T>(T v, T m) => X(v, m);
然åŽé‡è½½åˆ†è¾¨çŽ‡é€‰æ‹©X(object, object)
并åƒç¼–写代ç ä¸€æ ·ç¼–è¯‘ä»£ç :
static bool M<T>(T v, T m) => X((object)v, (object)m);
如果事实è¯æ˜ŽT
是int
,则两个int
都装在object
上。
让我å†æ¬¡å¼ºè°ƒä¸€ä¸‹ã€‚到抖动时,我们已ç»çŸ¥é“将调用哪个X
了;该决定是在C#编译时åšå‡ºçš„。 Cï¼ƒç¼–è¯‘å™¨çš„åŽŸå› æ˜¯â€œæˆ‘æœ‰ä¸¤ä¸ªT,我ä¸çŸ¥é“它们å¯ä»¥è½¬æ¢ä¸ºint,所以我必须选择对象版本â€ã€‚
这与C ++模æ¿ä»£ç 相å,åŽè€…为æ¯ä¸ªæ¨¡æ¿å®žä¾‹é‡æ–°ç¼–译该代ç ,并é‡æ–°æ‰§è¡Œé‡è½½è§£æžã€‚
è¿™æ ·å¯ä»¥å›žç”最åˆæ出的问题。
现在让我们进入奇怪的细节。
 Â在jit编译
M<int>
时,是å¦å…许抖动注æ„到M<int>
调用X(object, object)
,然åŽè°ƒç”¨object.Equals(object, object)
,已知struct S { public int x; public void M() { this.x += 1; } }
比较两个装箱的整数是å¦ç›¸ç‰ï¼Œå¹¶ç›´æŽ¥ç”Ÿæˆå°†ä¸¤ä¸ªæ•´æ•°ä»¥æœªè£…箱形å¼è¿›è¡Œæ¯”较的代ç ?
是的,å…许执行该优化。
 Â实际上å¯ä»¥æ‰§è¡Œä¼˜åŒ–å—?
æ®æˆ‘所知。抖动确实执行了一些内è”优化,但是æ®æˆ‘所知,它没有执行任何高级的内è”。
 Â在实践ä¸æ˜¯å¦å˜åœ¨æŠ–动导致拳击失败的情况?
是的ï¼
 Âä½ èƒ½ä¸¾ä¸€äº›ä¾‹åå—?
当然。考虑以下糟糕代ç :
S s = whatever;
s.M();
å½“æˆ‘ä»¬è¿™æ ·åšæ—¶ï¼š
this
会å‘生什么?值类型ä¸çš„ref S
ç‰æ•ˆäºŽç±»åž‹s
çš„å‚æ•°ã€‚å› æ¤ï¼Œæˆ‘们对M
è¿›è¡Œäº†å¼•ç”¨ï¼Œå¹¶å°†å…¶ä¼ é€’ç»™interface I
{
void M();
}
struct S : I { /* body as before */ }
,ä¾æ¤ç±»æŽ¨ã€‚
çŽ°åœ¨è€ƒè™‘ä»¥ä¸‹å‡ ç‚¹ï¼š
S s = whatever;
I i = s;
i.M();
现在å‡è®¾æˆ‘ä»¬è¿™æ ·åšï¼š
s
会å‘生什么?
I
转æ¢ä¸ºI
是装箱转æ¢ï¼Œå› æ¤æˆ‘们分é…一个盒å,使该盒å实现s
,并在该盒åä¸å¤åˆ¶i.M()
。 I
ä¼šå°†æ¡†ä½œä¸ºæŽ¥æ”¶æ–¹ä¼ é€’åˆ°æ¡†ä¸çš„s
的实现ä¸ã€‚然åŽï¼Œå°†å¼•ç”¨å¤åˆ¶åˆ°æ¡†ä¸çš„this
,并将引用作为M
ä¼ é€’åˆ°void Q<T>(T t) where T : I
{
t.M();
}
...
S s = whatever;
Q<S>(s);
。好å§ï¼ŒçŽ°åœ¨æ¥äº†ï¼Œè¿™å°†ä½¿æ‚¨å›°æƒ‘。
s
现在会å‘生什么?显然,我们将t
的副本å¤åˆ¶åˆ°S
ä¸ï¼Œæ²¡æœ‰è£…箱;两者å‡ä¸ºI.M
类型。但是:I
期望类型为t
的接收者,而S
的类型为t
。我们必须åšä»¥å‰åšè¿‡çš„事å—?我们是å¦å°†I
装到实现S.M
çš„ç›’åä¸ï¼Œç„¶åŽè¯¥ç›’å调用this
,其ä¸S.M
是对该盒å的引用?
ä¸ã€‚抖动会生æˆä»£ç ,该代ç å°†å–消装箱并直接以ref t
作为this
çš„æ–¹å¼è°ƒç”¨void Q<T>(T t) where T : I
{
t.M();
}
。
这是什么æ„æ€ï¼Ÿè¿™æ„味ç€ï¼š
void Q<T>(T t) where T : I
{
I i = t;
i.M();
}
和
t
ä¸ä¸€æ ·ï¼å‰è€…çªå˜S
ï¼Œå› ä¸ºè·³è¿‡äº†æ‹³å‡»ã€‚åŽé¢çš„框然åŽå¯¹æ¡†è¿›è¡Œå˜å¼‚。
这里的é‡ç‚¹åº”该是å¯å˜å€¼ç±»åž‹æ˜¯çº¯é‚ªæ¶çš„,您应该ä¸æƒœä¸€åˆ‡ä»£ä»·é¿å…使用它们。æ£å¦‚我们所看到的,您å¯ä»¥å¾ˆå®¹æ˜“地进入认为您应该对副本进行å˜å¼‚的情况,但您æ£åœ¨å¯¹åŽŸå§‹å˜å¼‚进行å˜å¼‚,或更糟的是,您认为您对原始物进行å˜å¼‚,但是您æ£åœ¨å˜å¼‚一个副本。å¤åˆ¶ã€‚
 Â什么奇异的é”法使它起作用?
使用sharplab.io并将我给出的方法å汇编为IL。仔细阅读IL。如果您ä¸äº†è§£ä»»ä½•å†…容,请查找。充分è¯æ˜Žäº†ä½¿æ¤ä¼˜åŒ–有效的所有神奇机制。
 ÂæŠ–åŠ¨æ€»æ˜¯è¿™æ ·åšå—?
ä¸ï¼ (您会知é“是å¦æŒ‰ç…§æˆ‘的建议阅读了所有文档。)
ä½†æ˜¯ï¼Œæž„å»ºæ— æ³•æ‰§è¡Œä¼˜åŒ–çš„æ–¹æ¡ˆæœ‰äº›æ£˜æ‰‹ã€‚æˆ‘ä¼šæŠŠå®ƒå½“ä½œä¸€ä¸ªéš¾é¢˜ï¼š
给我写一个程åºï¼Œå…¶ä¸æˆ‘们有一个实现接å£I
的结构类型T
。我们将类型å‚æ•°I
约æŸä¸ºT
,并用S
æž„é€ T t
ï¼Œå¹¶ä¼ å…¥t
。我们用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)
{
调用一个方法作为接收方,而抖动总是使接收方被装箱。
æ示:我预计被调用方法的å称ä¸åŒ…å«ä¸ƒä¸ªå—æ¯ã€‚我说的对å—?
挑战#2:一个问题:是å¦æœ‰å¯èƒ½ä½¿ç”¨æˆ‘之å‰å»ºè®®çš„相åŒæŠ€æœ¯æ¥è¯æ˜Žæ‹³å‡»å‘生? (该技术是:表明拳击一定是已ç»å‘ç”Ÿçš„ï¼Œå› ä¸ºå‰¯æœ¬è€Œä¸æ˜¯åŽŸå§‹å‰¯æœ¬å‘生了çªå˜ã€‚
 Â是å¦å˜åœ¨ä¸å¿…è¦çš„抖动盒情况?
是的ï¼å½“我在编译器上工作时,抖动并没有优化“从T到O的框,立å³å–消从O到T的框â€çš„指令åºåˆ—,有时C#编译器需è¦ç”Ÿæˆæ¤ç±»åºåˆ—以使验è¯è€…满æ„。我们è¦æ±‚实施优化;我ä¸çŸ¥é“有没有。
 Âä½ èƒ½ä¸¾ä¸ªä¾‹åå—?
好的。å‡è®¾æˆ‘们有
U
好的,现在您知é“int
的唯一å¯èƒ½ç±»åž‹æ˜¯t
ï¼Œå› æ¤u
应该å¯åˆ†é…ç»™u
å’Œ{{1 }}应该å¯åˆ†é…ç»™t
,对å—?但是CLR验è¯ç¨‹åºä¸ä¼šé‚£æ ·çœ‹ï¼Œå› æ¤æ‚¨å¯èƒ½ä¼šé‡åˆ°ç¼–译器必须生æˆå°†int
装箱到object
然åŽå†æ‹†ç®±åˆ°U
的代ç 的情况,是int
,所以往返是没有æ„义的。
 Â这是什么?
T
转æ¢ä¸ºobject
,那么该T
便会真æ£è½¬æ¢ä¸ºobject
。