Как получить FieldInfo поля массива?

Я пытаюсь получить информацию о поле значения массива из структуры. Пока у меня есть следующее, но я не вижу, как получить нужную информацию.

    [StructLayout(LayoutKind.Sequential)]
    public struct Test
    {
        public byte Byte1;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
        public Test2[] Test1;
    }

    BindingFlags struct_field_flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
    FieldInfo[] all_struct_fields = typeof(Test).GetFields(struct_field_flags);
    foreach (FieldInfo struct_field in all_struct_fields)
    {
        if(struct_field.FieldType.IsArray)
        {
           // Get FieldInfo for each value in the Test1 array within Test structure
        }
    }

Итак, если бы я сделал:

 Type array_type = struct_field.FieldType.GetElementType();

Это вернет тип Test2, но мне не нужен тип массива, мне нужны FieldInfo или поля этой структуры, чтобы я мог устанавливать значения из нее.


person SwDevMan81    schedule 03.08.2009    source источник


Ответы (3)


Извините за первоначальный неправильный ответ. Мне было лень создавать свой собственный тип Test2, поэтому вместо этого я использовал строку. Вот правильный ответ (надеюсь):

Я сделал то, что вы хотите сделать, со следующим кодом:

class Program
{
    static void Main(string[] args)
    {
        object sampleObject = GetSampleObject();
        FieldInfo[] testStructFields = typeof(Test).GetFields();

        foreach (FieldInfo testStructField in testStructFields)
        {
            if (testStructField.FieldType.IsArray)
            {
                // We can cast to ILIst because arrays implement it and we verfied that it is an array in the if statement
                System.Collections.IList sampleObject_test1 = (System.Collections.IList)testStructField.GetValue(sampleObject);
                // We can now get the first element of the array of Test2s:
                object sampleObject_test1_Element0 = sampleObject_test1[0];

                // I hope this the FieldInfo that you want to get:
                FieldInfo myValueFieldInfo = sampleObject_test1_Element0.GetType().GetField("MyValue");

                // Now it is possible to read and write values
                object sampleObject_test1_Element0_MyValue = myValueFieldInfo.GetValue(sampleObject_test1_Element0);
                Console.WriteLine(sampleObject_test1_Element0_MyValue); // prints 99
                myValueFieldInfo.SetValue(sampleObject_test1_Element0, 55);
                sampleObject_test1_Element0_MyValue = myValueFieldInfo.GetValue(sampleObject_test1_Element0);
                Console.WriteLine(sampleObject_test1_Element0_MyValue); // prints 55
            }
        }
    }

    static object GetSampleObject()
    {
        Test sampleTest = new Test();
        sampleTest.Test1 = new Test2[5];
        sampleTest.Test1[0] = new Test2() { MyValue = 99 };
        object sampleObject = sampleTest;
        return sampleObject;
    }
}

[StructLayout(LayoutKind.Sequential)]
public struct Test2
{
    public int MyValue;
}

[StructLayout(LayoutKind.Sequential)]
public struct Test
{
    public byte Byte1;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public Test2[] Test1;
}

Это самая важная строка:

FieldInfo myValueFieldInfo = sampleObject_test1_Element0.GetType().GetField("MyValue");

Это должно дать вам FieldInfo, о котором вы говорите.

person weiqure    schedule 03.08.2009

Что именно вы ищете? Для элементов в массиве нет нет FieldInfo... вы можете перебирать значения, получая массив (как Array) и повторяя его... просто используйте:

Array arr = (Array)field.GetValue(obj);
person Marc Gravell    schedule 03.08.2009
comment
Я хотел бы получить FieldInfo Test2, чтобы я мог устанавливать значения из этой структуры. - person SwDevMan81; 03.08.2009
comment
Для Test1 да, но я хочу его для массива Test2. Если это массив, я хочу получить FieldInfo типа массива, чтобы я мог выполнить field.SetValue(obj, value) для значения Test1. - person SwDevMan81; 03.08.2009
comment
Вы потеряли меня где-то между Test1 и Test2... если вы имеете в виду каждый экземпляр внутри массива, то относитесь к каждому экземпляру как к объекту... тогда у вас есть GetType() и т. д. Или используйте arr.GetType().GetElementType( ). Но нет поля, указывающего внутри массива. - person Marc Gravell; 03.08.2009

Проблема с методом @weiqure заключается в том, что он работает только в том случае, если в массиве уже есть хотя бы один элемент. Вот способ найти тип элемента массива, независимо от того, содержит он элементы или нет:

bool GetArrayElementType(FieldInfo field, out Type elementType)
{
    if (field.FieldType.IsArray && field.FieldType.FullName.EndsWith("[]"))
    {
        string fullName = field.FieldType.FullName.Substring(0, field.FieldType.FullName.Length - 2);
        elementType = Type.GetType(string.Format("{0},{1}", fullName, field.FieldType.Assembly.GetName().Name));
        return true;
    }
    elementType = null;
    return false;
}

И вот как вы могли бы использовать эту функцию:

void Test(object targetObject, string fieldName)
{
    FieldInfo field = targetObject.GetType().GetField(fieldName);
    Type elementType;
    bool success = GetArrayElementType(field, out elementType);
}
person intrepidis    schedule 01.12.2014
comment
Собственно, эта часть и не нужна: && field.FieldType.FullName.EndsWith("[]") ... но я подумал, что добавлю ее для полноты картины. - person intrepidis; 01.12.2014