How to Set Property Values using LINQ to Objects and Reflection

by Zoran Horvat
Aug 08, 2013

Reflection lets us set values of the properties without knowing actual properties, or even objects at compile time. But getting hold of property descriptors (PropertyInfo instances) may sometimes be a cumbersome task.

LINQ to Objects comes as a rescue when multiple properties need to be isolated from a given object. The code which includes LINQ query is easier to write and more readable than the code based on loops.

The following function accepts an object and a collection of name/value pairs, each pair representing one property returning integer value. Function finds all listed properties in the object and then sets their values.

T RehydrateObject<T>(T obj, IEnumerable<Tuple<string, int>> nameValues)
{

    object boxedCopy = RuntimeHelpers.GetObjectValue(obj);

    var propertyDescriptors =
        (from property in typeof(T).GetProperties()
         join nameValuePair in nameValues on property.Name equals nameValuePair.Item1
         select new
         {
             Property = property,
             Value = nameValuePair.Item2
         });

    foreach (var pd in propertyDescriptors)
        pd.Property.SetValue(boxedCopy, pd.Value);

    obj = (T)boxedCopy;

    return obj;

}

Observe the way in which received object was first boxed. This trick ensures that the function works fine with value types as well as with reference types. Please refer to How to Set Property Value using Reflection on a Value Type for details on this issue.

On a related note, name/value pairs collection used in this example was returned by DehydrateObject function, which is explained in How to Get Property Values using LINQ to Objects.

Example

Below is the source code of a console application which demonstrates the RehydrateObject method. When function listed above is applied to an instance of the Rectangle structure (value type), it extracts four integer properties from the collection and sets the corresponding Rectangle properties. In the second part of the test, function is applied to a class (reference type) and another collection of name/value pairs. In both cases, the rehydrated objects will have their properties set to values listed in the collection.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.CompilerServices;

namespace PropertySettingDemo
{
    class Program
    {

        static T RehydrateObject<T>(T obj, IEnumerable<Tuple<string, int>> nameValues)
        {
             ...
        }

        class DemoClass
        {
            public int A { get; set; }
            public int B { get; set; }
            public override string ToString()
            {
                return string.Format("{{A={0},B={1}}}", A, B);
            }
        }

        static void Main(string[] args)
        {

            Tuple<string, int>[] values = new Tuple<string, int>[]
            {
                new Tuple<string, int>("X", 20),
                new Tuple<string, int>("Y", 30),
                new Tuple<string, int>("Width", 150),
                new Tuple<string, int>("Height", 90)
            };

            Rectangle rect = RehydrateObject<Rectangle>(new Rectangle(), values);

            Console.WriteLine("Rectangle={0}", rect);

            values = new Tuple<string, int>[]
            {
                new Tuple<string, int>("A", 70),
                new Tuple<string, int>("B", 80)
            };

            DemoClass c = RehydrateObject<DemoClass>(new DemoClass(), values);

            Console.WriteLine("DemoClass={0}", c);

            Console.Write("Press ENTER to continue... ");
            Console.ReadLine();

        }
    }
}

When application is run, it produces output like this:

Rectangle={X=20,Y=30,Width=150,Height=90}
DemoClass={A=70,B=80}
Press ENTER to continue...