在这种情况下,C#泛型是否阻止结构体的自动装箱?

前端之家收集整理的这篇文章主要介绍了在这种情况下,C#泛型是否阻止结构体的自动装箱?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
通常,将struct S作为接口处理,我将触发结构的自动装箱,如果经常执行,可能会影响性能.但是,如果我写一个类型参数T:I的泛型方法,并用S调用它,那么编译器会省略这个拳击,因为它知道类型S并且不必使用接口?

这段代码显示了我的观点:

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中来调用接口方法

解决方法

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,否则value-type将被传递到任何一个方法中的值复制!

当我取消对UseMyStruct(only)的调用时,该方法将我们的值类型中的“counter”移动到前面一个位置.如果它在值类型的盒装副本中这样做,我们不会在结构体的原始实例中看到它.

要看看与拳击有什么区别,请尝试调用UseMyStructAndBox(再次注释UseMyStruct).它在演员创建一个框,MoveNext发生在副本上.所以输出是不同的!

对于不喜欢(或混淆)参考的人,只需从方法内写出“电流”.然后我们可以摆脱参考.例:

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);
}
原文链接:https://www.f2er.com/csharp/96847.html

猜你在找的C#相关文章