HelterSkelter HelterSkelter - 21 days ago 5
C# Question

Access a certain unknown field of a known class using reflection

Say I have the following class:

class Person
{
public FirstType firstField ; // has a getter-setter
public SecondType secondField; // has a getter-setter
// more fields of other types
}


I want to build a function that accepts a
Person
class as its first parameter, and the type of one of the first parameter's fields as its second parameter - With the assumption that
Person
's fields are of distinct types.

My aim is to be able to use reflection on the second parameter, and then use some equivalent of a dot notation to access the passed class.

public void SetPersonField(Person person, <should it be Type?> personFieldType)
{
// accessing person's correct field type
}


How can it be done?

Answer

It can be easily done with reflection: you can acquire all public properties of a type, find the one of given type, and sets its value in the context of passed person instance.

I would also recommend using generic method for slightly better type safety and more laconic usage:

public static void SetPersonField<T>(Person person, T value)
{
    typeof (Person)
        .GetProperties()
        .Single(p => p.PropertyType == typeof(T))
        .SetValue(person, value);
}

// Usage (both are correct):
SetPersonField(person, FirstType.EnumValue);
SetPersonField<FirstType>(person, FirstType.EnumValue);

You even don't need to specify generic type since it can be understood from input parameter.

Note that .Single will throw an exception if there are no property of this type, or if there is more than one property of this type. If either existence or uniqueness is not guaranteed, you need to handle it in your SetPersonField method.
Also, always keep in mind the huge performance drop when using reflection.

What about being more generic?

You can implement a more generic method which will support any types of properties and objects:

public static void SetField<TObject, TProperty>(TObject obj, TProperty value)
{
    typeof(TObject)
        .GetProperties()
        .Single(p => p.PropertyType == typeof(TProperty))
        .SetValue(obj, value);
}

var person = new Person();
SetField(person, 123); // finds the only int property and sets its value
SetField(person, FirstType.EnumValue); // find the only FirstType property
SetField<Person, DateTime?>(person, DateTime.Now); // finds the only DateTime? property

Note that for some specific types (f.i., Nullable) you will need to explicitly specify types, since it cannot be understood from your data.