http://www.codinghelmet.com/  

Wear a helmet. Even when coding.

hints > linq-property-setter

How to Set Property Values using LINQ to Objects and Reflection
by Zoran Horvat @zoranh75

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...

See also:

Published: Aug 8, 2013; Modified: Aug 11, 2013

ZORAN HORVAT

Zoran is software architect dedicated to clean design and CTO in a growing software company. Since 2014 Zoran is an author at Pluralsight where he is preparing a series of courses on design patterns, writing unit and integration tests and applying methods to improve code design and long-term maintainability.

Follow him on Twitter @zoranh75 to receive updates and links to new articles.

Watch Zoran's video courses at pluralsight.com (requires registration):

Tactical Design Patterns in .NET: Managing Responsibilities

Applying a design pattern to a real-world problem is not as straightforward as literature implicitly tells us. It is a more engaged process. This course gives an insight into tactical decisions we need to make when applying design patterns that have to do with separating and implementing class responsibilities. More...

Tactical Design Patterns in .NET: Control Flow

Improve your skills in writing simpler and safer code by applying coding practices and design patterns that are affecting control flow. More...

Improving Testability Through Design

This course tackles the issues of designing a complex application so that it can be covered with high quality tests. More...

Share this article

webmasters