【问题标题】:C# reflection: getting the values of an arrayC# 反射:获取数组的值
【发布时间】:2013-10-13 21:48:14
【问题描述】:

我正在尝试编写一个反射类(用于自定义序列化)。 我对遍历数组的语法感到困惑。 以下适用于非数组,但我缺少数组部分,并且无法从这里的其他答案中解开它(其中一些无法编译)......

要实现反序列化,必须获得对目标类中每个对象的可写引用,以便从先前序列化的数据中设置它们的值。

提前感谢任何提示!

    private static void diagPrint(Object val)
    {
        if (val == null)
            return; // whoops
        Type t = val.GetType();
        string r = "";
        if (t.IsArray)
        {
            Type t_item = t.GetElementType();
            r += "Type=" + t_item.Name + "[], value=[";
            //
            // ??? OK, now what ? How to iterate through the elements of the array ???
            // Needs to work for arrays of simple type like Bool or arrays of objects...
            //
            r += "]";
        }
        else
        {
            r += "Type=" + t.Name + ", value=";
            r += val.ToString();
        }
        MessageBox.Show(r);
    }

【问题讨论】:

  • 你真的需要反射还是只需要遍历一些对象?
  • 考虑到数组一般会包含很多项,你想如何处理所有项?您的代码似乎处理 r 变量的单个值
  • @ErikPhilips 答案是 java,而不是 c#。但它基本上与stackoverflow.com/questions/104603/… 完全相同
  • 仍有问题。我在下面发布的答案适用于阅读结构,但不适用于反序列化。我需要的是对类中的对象或属性的 WRITEABLE 引用,但是“foreach”或“[n] subscripting”会产生只读引用,这些引用不能用作填充对象的函数的“ref”参数串行数据存储。 Aaarrrgggg....
  • @DaveNadler 1.不要将部分问题发布到答案中。没有人会看到它。您可以使用编辑您的问题(编辑按钮)。 2. 你的代码工作正常。向我们展示问题代码,以便我们了解您尝试实现的目标和问题所在。

标签: c# arrays reflection


【解决方案1】:

最简单的方法是将对象转换为IEnumerable,由数组实现。

IEnumerable items = val as IEnumerable;
foreach (object o in items)
{
    r += ((o != null) ? o.ToString() : "") + ", ";
}

【讨论】:

  • 你的意思是:IEnumerable items = val as IEnumerable;例如,对于 Bool 数组,items 为 null...
  • 不,只是普通的 IEnumerable
【解决方案2】:

要遍历一个数组,你可以使用IEnumerable interface

IEnumerable array = val as IEnumerable;
if (array != null)
{
    foreach (var element in array)
    {
        MessageBox.Show(element.ToString());
    }
}

每个array 都实现IEnumerable

【讨论】:

【解决方案3】:

除了其他答案,你还可以使用Array类的GetValue。所有数组都继承自Array,所以如果IsArray 为真,您可以转换为Array

请注意,这实际上只有在您想要处理多维数组时才需要。在大多数情况下,您只需转换为 IEnumerable。如果您只想枚举所有值,您甚至可以只使用多维数组

【讨论】:

    【解决方案4】:

    这是发货时的答案。我最初错过的重要部分是:

    • 您不能写入 IEnumerable (foreach) 内的元素,
    • 忘记尝试强制转换为数组并使用 [] 运算符(只需使用 get/set 值),
    • 有时在你意想不到的地方需要拳击

    请注意,此序列化程序适用于 FIXED SIZE 类(属性类用于指定字符串长度,反序列化的目标必须具有所有组件的默认初始化并且没有空值)。这用于 C# 内置序列化程序过于冗长而无法将值存储到空间受限的嵌入式设备的闪存中的情况。它不支持多维数组(读者练习)。

    希望有人觉得这有帮助,感谢您的建议,

    最好的问候,戴夫

        private static void navelGaze(string name, int level, ref object val, int storageSize)
        {
            Debug.Assert(val != null); // can happen with an unitialized string (please init to "")
            Type t = val.GetType();
            StringBuilder diagString = new StringBuilder(100);
            diagString.Append(name); diagString.Append(": ");
            if (t.IsArray)
            {
                Type t_item = t.GetElementType();
                Array ar = val as Array;
                int len = ar.Length;
                diagString.Append("Type="); diagString.Append(t_item.Name);
                diagString.Append("["); diagString.Append(len); diagString.Append("]");
                if (t_item.BaseType.Name == "ValueType")
                {
                    // array of primitive types like Bool or Int32...
                    diagString.Append(", value=[");
                    // Because C# does not permit modification of the iteration object
                    // in "foreach", nor subscript operations on an array of primitive values,
                    // use "GetValue/Setvalue" and a regular index iteration.
                    for(int idx=0; idx<len; idx++) {
                        object arrayElementBoxObj = ar.GetValue(idx);
                        Munger(ref arrayElementBoxObj, 0);
                        diagString.Append(arrayElementBoxObj.ToString());
                        diagString.Append(", ");
                        if (currentOperation == SerializerOperation_T.Deserialize)
                            ar.SetValue(arrayElementBoxObj, idx);
                    }
                    diagString.Append("]");
                    WriteDiagnostic(level, diagString.ToString());
                    return;
                }
                else
                {
                    // This is an array of a complex type; recurse for each element in the array...
                    WriteDiagnostic(level, diagString.ToString());
                    // The following cast operation is required to subscript 'ar'...
                    // Note an array of a primitive type like 'int' cannot be cast to an array of objects.
                    object[] vResObjArray = (object[])ar;
                    for(int i=0; i<len; i++) {
                        object boxObj = vResObjArray[i];
                        navelGaze(name + "[" + i + "]", level + 1, ref boxObj, 0);
                        if (currentOperation == SerializerOperation_T.Deserialize)
                        {
                            // Setting vResObjArray[x] DOES set the original object passed into
                            // this function, as required for deserialization.
                            vResObjArray[i] = boxObj;
                        }
                    }
                    return;
                }
            }
            else if (t.Name == "String")
            {
                // 'String' is actually a class, but normal class handling below blows up...
                diagString.Append("Type="); diagString.Append(t.Name);
                diagString.Append(", value=");
                Munger(ref val, storageSize);
                diagString.Append(val.ToString());
            }
            else if (t.IsClass)
            {
                // Decompose class and recurse over members
                WriteDiagnostic(level, diagString + "Class " + t.Name);
                // Note that custom attributes are associated with the class's fields and properties,
                // NOT the type of the value of the fields/properties, so this must be checked here
                // prior recursion to process the values...
                // GetFields does not get the PROPERTIES of the object, that's very annoying...
                FieldInfo[] fi = val.GetType().GetFields();
                foreach (FieldInfo f in fi)
                {
                    if (f.IsStatic) continue; // ignore class constants
                    // Skip this if the FIELD is marked [HSB_GUI_SerializeSuppress]
                    HSB_GUI_SerializeSuppressAttribute[] GUI_field_suppressSerializationAtt =
                        (HSB_GUI_SerializeSuppressAttribute[])
                        f.GetCustomAttributes(typeof(HSB_GUI_SerializeSuppressAttribute), true);
                    if (GUI_field_suppressSerializationAtt.Length > 0)
                        continue; // this field is marked with "suppress serialization to GUI save are"
                    // Get optional size specifier (required for strings)
                    int nextLevelStorageSize = 0;
                    HSB_GUI_SerializableAttribute[] HSB_GUI_SerializableAtt =
                        (HSB_GUI_SerializableAttribute[])
                        f.GetCustomAttributes(typeof(HSB_GUI_SerializableAttribute), true);
                    if (HSB_GUI_SerializableAtt.Length > 0)
                        nextLevelStorageSize = HSB_GUI_SerializableAtt[0].StorageLength;
                    // box, and gaze into this field...
                    object boxObj = f.GetValue(val);
                    // could replace null with default object constructed here
                    navelGaze(f.Name, level + 1, ref boxObj, nextLevelStorageSize);
                    if (currentOperation == SerializerOperation_T.Deserialize)
                        f.SetValue(val, boxObj);
                }
                // Now iterate over the PROPERTIES
                foreach (PropertyInfo prop in /*typeof(T)*/ val.GetType().GetProperties())
                {
                    // Skip this if the PROPERTY is marked [HSB_GUI_SerializeSuppress]
                    HSB_GUI_SerializeSuppressAttribute[] GUI_prop_suppressSerializationAtt =
                        (HSB_GUI_SerializeSuppressAttribute[])
                        prop.GetCustomAttributes(typeof(HSB_GUI_SerializeSuppressAttribute), true);
                    if (GUI_prop_suppressSerializationAtt.Length > 0)
                        continue; // this property is marked with "suppress serialization to GUI save are"
                    // not relevant; does not occur: if (!type.IsSerializable) continue;
                    // Get optional size specifier (required for strings)
                    int nextLevelStorageSize = 0;
                    HSB_GUI_SerializableAttribute[] HSB_GUI_SerializableAtt =
                        (HSB_GUI_SerializableAttribute[])
                        prop.GetCustomAttributes(typeof(HSB_GUI_SerializableAttribute), true);
                    if (HSB_GUI_SerializableAtt.Length > 0)
                        nextLevelStorageSize = HSB_GUI_SerializableAtt[0].StorageLength;
                    // box, and gaze into this field...
                    object boxObj = prop.GetValue(val, null);
                    // could replace null with default object constructed here
                    navelGaze("Property " + prop.Name, level + 1, ref boxObj, nextLevelStorageSize);
                    if (currentOperation == SerializerOperation_T.Deserialize)
                        prop.SetValue(val, boxObj, null);
                }
                return;
            }
            else if (t.IsEnum)
            {
                Munger(ref val, 0);
                diagString.Append("Enum ("); diagString.Append(t.Name); diagString.Append("), value=");
                diagString.Append(val.ToString()); diagString.Append(", raw value="); diagString.Append((int)val);
            }
            else
            {
                Munger(ref val, 0);
                diagString.Append("Type="); diagString.Append(t.Name);
                diagString.Append(", value="); diagString.Append(val.ToString());
            }
            WriteDiagnostic(level,diagString.ToString());
        }
    
        public static HSB_Settings_Class DeserializeResult(byte[] datastream)
        {
            Debug.Assert(datastream.Length == 0x0600);
            idx = 0;
            buf = datastream;
            currentOperation = SerializerOperation_T.Deserialize;
            HSB_Settings_Class new_HSB_settings = new HSB_Settings_Class();
            object boxObj = new_HSB_settings;
            navelGaze("DeserializeResult", 0, ref boxObj, 0);
            new_HSB_settings = (HSB_Settings_Class)boxObj;
            Console.WriteLine("==== Deserialization used a total of " + idx.ToString() + " bytes (out of 1536 available) ====");
            return new_HSB_settings;
        }
    
        public static byte[] SerializeHSBsettings(ref HSB_Settings_Class hsbset)
        {
            idx = 0;
            currentOperation = SerializerOperation_T.Serialize;
            object boxObj = hsbset;
            navelGaze("SerializeHSB", 0, ref boxObj, 0);
            Console.WriteLine("==== Serialization used a total of "+idx.ToString() + " bytes (out of 1536 available) ====");
            return buf;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-05
      • 2010-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多