C# 如何访问私人列表<;T>;成员?

C# 如何访问私人列表<;T>;成员?,c#,unity3d,unity5,C#,Unity3d,Unity5,一般来说,在C#中使用List比使用T[]更方便。但是,有时探查器会显示,与本机实现的大容量操作(如Array.Copy和Buffer.BlockCopy)相比,该列表会带来显著的性能损失。此外,不可能获取指向列表元素的指针 这使得在Unity中使用动态网格有些痛苦。如果我们能够访问T[]列表,其中一些问题可能会得到缓解。这是否可能在没有重大开销的情况下实现?(CPU或垃圾)使用反射总是可能的。这会为调用GetValue()生成几百字节的垃圾。它也不是很快;按40个列表访问的顺序 // He

一般来说,在C#中使用List比使用T[]更方便。但是,有时探查器会显示,与本机实现的大容量操作(如Array.Copy和Buffer.BlockCopy)相比,该列表会带来显著的性能损失。此外,不可能获取指向列表元素的指针


这使得在Unity中使用动态网格有些痛苦。如果我们能够访问T[]列表,其中一些问题可能会得到缓解。这是否可能在没有重大开销的情况下实现?(CPU或垃圾)

使用反射总是可能的。这会为调用GetValue()生成几百字节的垃圾。它也不是很快;按40个列表访问的顺序

  // 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);
  }
//用于获取和缓存FieldInfo值的帮助器类
类字段查找{
字符串sm_名称;
字典sm_缓存;
公共字段查找(字符串名称){
sm_name=名称;
sm_cache=新字典();
}
公共字段信息获取(t型){
试一试{
返回sm_缓存[t];
}catch(KeyNotFoundException){
var field=sm_缓存[t]=t.GetField(
sm_名称,
System.Reflection.BindingFlags.NonPublic|
System.Reflection.BindingFlags.GetField|
System.Reflection.BindingFlags.Instance);
返回字段;
}
}
}
静态FieldLookup sm_items=新的FieldLookup(“_items”);
公共静态T[]GetBackingArray(此列表){
return(T[])sm_items.Get(typeof(List)).GetValue(List);
}

使用反射始终是可能的。这会为调用GetValue()生成几百字节的垃圾。它也不是很快;按40个列表访问的顺序

  // 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);
  }
//用于获取和缓存FieldInfo值的帮助器类
类字段查找{
字符串sm_名称;
字典sm_缓存;
公共字段查找(字符串名称){
sm_name=名称;
sm_cache=新字典();
}
公共字段信息获取(t型){
试一试{
返回sm_缓存[t];
}catch(KeyNotFoundException){
var field=sm_缓存[t]=t.GetField(
sm_名称,
System.Reflection.BindingFlags.NonPublic|
System.Reflection.BindingFlags.GetField|
System.Reflection.BindingFlags.Instance);
返回字段;
}
}
}
静态FieldLookup sm_items=新的FieldLookup(“_items”);
公共静态T[]GetBackingArray(此列表){
return(T[])sm_items.Get(typeof(List)).GetValue(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;
  }
[StructLayout(LayoutKind.Explicit)]
公共结构转换助手
其中TFrom:class
在哪里上课{
[FieldOffset(0)]早就公开了;
[FieldOffset(8)]来自输入的公共TF;
[FieldOffset(16)]公共TTo输出;
静态公共TTo转换(TFrom thing){
var helper=newconverthelper{input=thing};
不安全{
长*危险=&helper.before;
危险[2]=危险[1];//即,输出=输入
}
var ret=helper.output;
helper.input=null;
helper.output=null;
返回ret;
}
}
班级名单{
公共T[]_项目;
}
公共静态T[]GetBackingArray(此列表){
返回ConvertHelper.Convert(列表)。\u项;
}

如果您知道列表的布局,那么您可以使用肮脏的技巧来强制转换托管对象引用。除非您愿意在运行的每个目标平台上进行测试,并在每次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;
  }
[StructLayout(LayoutKind.Explicit)]
公共结构转换助手
其中TFrom:class
在哪里上课{
[FieldOffset(0)]早就公开了;
[FieldOffset(8)]来自输入的公共TF;
[FieldOffset(16)]公共TTo输出;
静态公共TTo转换(TFrom thing){
var helper=newconverthelper{input=thing};
不安全{
长*危险=&helper.before;
危险[2]=危险[1];//即,输出=输入
}
var ret=helper.output;
helper.input=null;
helper.output=null;
返回ret;
}
}
班级名单{
公共T[]_项目;
}
公共静态T[]GetBackingArray(此列表){
返回ConvertHelper.Convert(列表)。\u项;
}

为什么不为这种情况实现自定义列表?因为只有自定义API才会接受自定义列表。平台API不会。@PaulDuBois:Platform API应该期望实现任何可以在自定义类中实现的东西。平台API中实际需要实例的大多数示例都是API错误设计的可悲纪念物。@PaulDuBois-我们所做的只是动态网格。我只使用普通的旧数组。明确地说,在任何“通用”Unity编程中,我从来没有使用过列表以外的任何东西,使用数组是毫无意义的。但对于网格,它一直都是数组。(在iOS中,我只是得到一块ram,自己做!)纯粹是FTR,我认为,当你在网格级别进行交易时,使用列表没有任何好处。你所想的一切都是算法上的偏移量。检查一下:为什么不为这种情况实现自定义列表?因为只有自定义API才会接受自定义列表。普拉福