2

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

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

提前感谢您的任何提示!

    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);
    }
4

4 回答 4

7

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

IEnumerable items = val as IEnumerable;
foreach (object o in items)
{
    r += ((o != null) ? o.ToString() : "") + ", ";
}
于 2013-10-13T21:54:32.717 回答
4

要遍历数组,您可以使用IEnumerable interface

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

每个数组都实现IEnumerable.

于 2013-10-13T21:55:50.427 回答
2

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

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

于 2013-10-13T22:06:08.200 回答
0

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

  • 您不能写入 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;
    }
于 2013-11-03T16:45:39.570 回答