views:

108

answers:

4

Hey guys,

I need to assign an array to a field. I dont know the fields type, but I do have a reference to an instance and the name of the field. I can assume the array can be casted to the fields type. Can this be done?

Bas

Edit:

Hopefully this code will clarify what Im trying to do, this causes an exception in assign:

class MyClass
{
    static void Main()
    {
        MyClass t = new MyClass();
        A a = new A();
        C[] c = new C[] {new B()};
        t.Assign(a, "field", c);
    }

    void Assign(object obj, string field, object[] value)
    {
        // crashes
        obj.GetType().GetField(field).SetValue(obj, value);
    }
}

class A
{
    public B[] field;
}

class B : C { }

class C { }
+5  A: 
instance.GetType()
    .GetField("fieldName", BindingFlags.Instance | BindingFlags.NonPublic)
    .SetValue(instance, array);
Darin Dimitrov
+1  A: 

For more information see the reflection page on MSDN.

ChrisF
A: 

If the code which calls this is not timecritical you can simply use the FieldInfos SetValue()

obj.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic).SetValue(obj, newFieldValue);

If the code will be called more often you might want to dynamically compile a setter-delegate. This can be done e.g. using lightweight code generation:

Action<TObject, TField> ConstructGetter(string fieldName)
{
    System.Reflection.FieldInfo field = typeof(TObject).GetField(fieldName);
    DynamicMethod method = new DynamicMethod(typeof(TObject).ToString() + ":" + "Set:" + name,
            null, new Type[] { typeof(TObject), typeof(TField) }, typeof(TObject));
 ILGenerator generator = method.GetILGenerator();
 generator.Emit(OpCodes.Ldarg_0);
 generator.Emit(OpCodes.Ldarg_1);
 generator.Emit(OpCodes.Stfld, field);
 generator.Emit(OpCodes.Ret);
 return method.CreateDelegate(typeof(Action<TObject, TField>)) as Action<TObject, TField>;
}
Grizzly
A: 

So a kind soul showed me the solution, enjoy : )

using System;
using System.Reflection;

class MyClass
{
    static void Main()
    {
        MyClass t = new MyClass();
        A a = new A();
        C[] c = new C[] {new B()};
        t.Assign(a, "field", c);
    }

    void Assign(object obj, string field, object[] value)
    {
        FieldInfo pinfo = obj.GetType().GetField(field);
        Array array = Array.CreateInstance(pinfo.FieldType.GetElementType(), value.Length);
        value.CopyTo(array, 0);
        pinfo.SetValue(obj, array);
    }
}

class A
{
    public B[] field;
}

class B : C { }

class C { }
Bas Smit