如何访问私人List <t>成员?

时间:2016-02-23 21:34:49

标签: c# unity3d unity5

通常,在C#中使用List比使用T []更方便。但是,有时候分析器显示List与Array.Copy和Buffer.BlockCopy等本机实现的批量操作相比具有显着的性能损失。此外,无法获得指向List&lt;&gt;的指针。元件。

这使得使用Unity中的动态网格有点痛苦。如果我们可以访问 T [] List._items ,可以减轻其中一些问题。这可能没有显着的开销吗? (无论是CPU还是垃圾)

2 个答案:

答案 0 :(得分:0)

始终可以使用反射。这会为 GetValue()的调用生成几百个字节的垃圾。它也不是很快;大约40列表&lt; T>访问。

  // Helper class for fetching and caching FieldInfo values
  class FieldLookup {
    string sm_name;
    Dictionary<Type, FieldInfo> sm_cache;
    public FieldLookup(string name) {
      sm_name = name;
      sm_cache = new Dictionary<Type, FieldInfo>();
    }
    public FieldInfo Get(Type t) {
      try {
        return sm_cache[t];
      } catch (KeyNotFoundException) {
        var field = sm_cache[t] = t.GetField(
          sm_name,
          System.Reflection.BindingFlags.NonPublic |
          System.Reflection.BindingFlags.GetField |
          System.Reflection.BindingFlags.Instance);
        return field;
      }
    }
  }

  static FieldLookup sm_items = new FieldLookup("_items");

  public static T[] GetBackingArray<T>(this List<T> list) {
    return (T[])sm_items.Get(typeof(List<T>)).GetValue(list);
  }

答案 1 :(得分:0)

如果您知道List的布局,那么您可以使用脏技巧来转换托管对象引用。除非您愿意在所运行的每个目标平台上进行测试,否则不要使用它,并在每次Unity升级时重新测试。

最危险的是它打破了关于运行时和对象的编译类型的不变量。编译器将为TTo类型的对象生成代码,但对象的RTTI字段仍将显示TFrom类型的对象。

  [StructLayout(LayoutKind.Explicit)]
  public struct ConvertHelper<TFrom, TTo>
      where TFrom : class
      where TTo : class {
    [FieldOffset( 0)] public long before;
    [FieldOffset( 8)] public TFrom input;
    [FieldOffset(16)] public TTo output;

    static public TTo Convert(TFrom thing) {
      var helper = new ConvertHelper<TFrom, TTo> { input = thing };
      unsafe {
        long* dangerous = &helper.before;
        dangerous[2] = dangerous[1];  // ie, output = input
      }
      var ret = helper.output;
      helper.input = null;
      helper.output = null;
      return ret;
    }
  }

  class PublicList<T> {
    public T[] _items;
  }

  public static T[] GetBackingArray<T>(this List<T> list) {
    return ConvertHelper<List<T>, PublicList<T>>.Convert(list)._items;
  }