How do I get the FieldInfo of an array field?
Asked Answered
E

3

5

I'm trying to get the field info of an array value from within a struct. So far I have the following, but I dont see how to get the infomration I want.

    [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
        }
    }

So if I did:

 Type array_type = struct_field.FieldType.GetElementType();

This would return Test2 type, but I dont want the type of the array, I want the FieldInfo or Fields of that structure so I can set values from within it.

Elvinaelvira answered 3/8, 2009 at 14:55 Comment(0)
A
6

Sorry for the initial wrong answer. I was too lazy to create my own Test2 type so I used a string instead. Here's the right answer (hopefully):

I did what you want to do with the following code:

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

This is the most important line:

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

It should give you the FieldInfo that you are talking about.

Ask answered 3/8, 2009 at 15:38 Comment(0)
M
3

What exactly are you after? There is no FieldInfo for the items in the array... you can iterate the values by getting the array (as Array) and iterating it... just use:

Array arr = (Array)field.GetValue(obj);
Malang answered 3/8, 2009 at 15:2 Comment(3)
I would like to get the FieldInfo of Test2 so that I could set values from within that structureElvinaelvira
For Test1 yes, but I want it for the array of Test2's. If it is an array, I want to get the FieldInfo of the array type so that I can do field.SetValue(obj, value) for the Test1 value.Elvinaelvira
You've lost me somewhere between Test1 and Test2... if you mean each instance inside the array, then treat each instance as an object... then you have GetType() etc. Or use arr.GetType().GetElementType(). But there is no field that points inside the array.Malang
M
0

The problem with @weiqure's technique is that it only works if the array already has at least one element in it. Here is a way to find the array's element type, whether it contains elements or not:

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

And here is how you would use that function:

void Test(object targetObject, string fieldName)
{
    FieldInfo field = targetObject.GetType().GetField(fieldName);
    Type elementType;
    bool success = GetArrayElementType(field, out elementType);
}
Mathildamathilde answered 1/12, 2014 at 1:27 Comment(1)
Actually, this part is unnecessary: && field.FieldType.FullName.EndsWith("[]") ... but I thought I would add it for completeness.Mathildamathilde

© 2022 - 2024 — McMap. All rights reserved.