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 object-oriented and functional design, 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):

Making Your C# Code More Object-Oriented

This course will help leverage your conceptual understanding to produce proper object-oriented code, where objects will completely replace procedural code for the sake of flexibility and maintainability. More...

Advanced Defensive Programming Techniques

This course will lead you step by step through the process of developing defensive design practices, which can substitute common defensive coding, for the better of software design and implementation. More...

Tactical Design Patterns in .NET: Creating Objects

This course sheds light on issues that arise when implementing creational design patterns and then provides practical solutions that will make our code easier to write and more stable when running. More...

Tactical Design Patterns in .NET: Managing Responsibilities

Applying a design pattern to a real-world problem is not as straight-forward as literature implicitly tells us. It is a more engaged process. This course gives an insight to 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...

Writing Highly Maintainable Unit Tests

This course will teach you how to develop maintainable and sustainable tests as your production code grows and develops. 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