gpt4 book ai didi

c# - 在这种情况下,C# 泛型会阻止结构的自动装箱吗?

转载 作者:可可西里 更新时间:2023-11-01 09:08:02 24 4
gpt4 key购买 nike

通常,将结构 S 视为接口(interface) I 会触发结构的自动装箱,如果经常这样做会对性能产生影响。但是,如果我编写一个采用类型参数 T : I 的泛型方法并使用 S 调用它,那么编译器是否会省略装箱,因为它知道类型 S 并没有使用接口(interface)?

这段代码表明了我的观点:

interface I{
void foo();
}

struct S : I {
public void foo() { /* do something */ }
}

class Y {

void doFoo(I i){
i.foo();
}
void doFooGeneric<T>(T t) where T : I {
t.foo(); // <--- Will an S be boxed here??
}

public static void Main(string[] args){
S x;
doFoo(x); // x is boxed
doFooGeneric(x); // x is not boxed, at least not here, right?
}

}

doFoo 方法在 I 类型的对象上调用 foo(),所以一旦我们用 S< 调用它S 将被装箱。 doFooGeneric 方法做同样的事情。然而,一旦我们用 S 调用它,可能不需要自动装箱,因为运行时知道如何在 S 上调用 foo() .但这会完成吗?或者运行时会盲目地将 S 装箱到 I 以调用接口(interface)方法?

最佳答案

void doFooGeneric<T>(T t) where T : I {
t.foo(); // <--- Will an S be boxed here??
}

那里将避免拳击!

结构类型 S是密封的。对于类型参数的值类型版本 T你的方法doFooGeneric上面,C# 编译器给出了直接调用相关结构成员的代码,没有装箱。

这很酷。

有关一些技术细节,请参阅 Sameer 的回答。


好的,所以我想出了一个这样的例子。如果有人有一些更好的例子,我会对更好的例子感兴趣:

using System;
using System.Collections.Generic;

namespace AvoidBoxing
{
static class Program
{
static void Main()
{
var myStruct = new List<int> { 10, 20, 30, }.GetEnumerator();
myStruct.MoveNext(); // moves to '10' in list

//
// UNCOMMENT ONLY *ONE* OF THESE CALLS:
//

//UseMyStruct(ref myStruct);
//UseMyStructAndBox(ref myStruct);

Console.WriteLine("After call, current is now: " + myStruct.Current); // 10 or 20?
}

static void UseMyStruct<T>(ref T myStruct) where T : IEnumerator<int>
{
myStruct.MoveNext();
}

static void UseMyStructAndBox<T>(ref T myStruct)
{
((IEnumerator<int>)myStruct).MoveNext();
}
}
}

这里是 myStruct 的类型是一个可变值类型,它保留对 List<> 的引用, 并且还持有记住 List<> 中的索引的“计数器”我们已经达到了现在。

我不得不使用 ref ,否则当传递给任一方法时,值类型将按值复制!

当我取消对 UseMyStruct 的调用的注释时(仅),此方法将我们的值类型中的“计数器”向前移动一个位置。如果它在值类型的盒装副本中这样做,我们将不会在结构的原始实例中看到它。

要查看装箱有何不同,请尝试调用 UseMyStructAndBox相反(再次评论 UseMyStruct)。它在类型转换上创建了一个盒子,并且 MoveNext发生在副本上。所以输出是不同的!


致那些对 ref 不满意(或感到困惑)的人, 就写出 Current而不是从方法内部。然后我们可以去掉ref .示例:

static void F<T>(T t) where T : IEnumerator<int>
{
t.MoveNext(); // OK, not boxed
Console.WriteLine(t.Current);
}

static void G<T>(T t) where T : IEnumerator<int>
{
((IEnumerator<int>)t).MoveNext(); // We said "Box!", it will box; 'Move' happens to a copy
Console.WriteLine(t.Current);
}

关于c# - 在这种情况下,C# 泛型会阻止结构的自动装箱吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31457682/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com