Krishna
Krishna

Reputation: 347

C# Dynamic Projection of all properties into one object

I want to Combine properties of two anonymous objects into one.

var obj = new[]
            {
                new {ClientId = 7, ClientName = "ACME Inc.", Jobs = 5},
                new {ClientId = 8, ClientName = "JUST Inc.", Jobs = 25}
            };
            var obj2 = new[]
            {
                new {ClientId = 7, ClientAddress = "Gypsy Ave", ClientState = "KY"},
                new {ClientId = 8, ClientAddress = "Dorky Rd", ClientState = "NC"}
            };

I want to join the above 2 anonymous objects on client Id and create object with all props from obj and obj2.

var jn = (from i in obj
                join j in obj2 on i.ClientId equals j.ClientId
                select new
                {
                    i.*,j.*
                });

Is there a way to achieve this using dynamics or reflection? I think I'm looking for a generic dynamic projection kinda solution.

Upvotes: 0

Views: 1073

Answers (1)

Alan
Alan

Reputation: 116

You can use reflection to take the results within the variable "jn" and convert them to Dictionary<string, object>.

Modify your linq expression:

var jn = (from i in obj
    join j in obj2 on i.ClientId equals j.ClientId
    select new
    {
        i, j
    });

Get the properties of the joined type:

//Pass items within variable "jn"
private static Dictionary<string, object> joinLinqObjectProperties(object obj)
{
    Dictionary<string, object> toReturn = new Dictionary<string, object>();

    //This will be "i" and "j" from the linq select
    var joinedObjectProperties = obj.GetType().GetProperties();

    foreach (var prop in joinedObjectProperties)
    {
        var joinedObjectItem = prop.GetValue(obj, null);

        //This will be the properties of the anonymous type
        var subObjectProperties = joinedObjectItem.GetType().GetProperties();

        foreach (var subProp in subObjectProperties)
        {
            if (!toReturn.ContainsKey(subProp.Name))
            {
                toReturn.Add(subProp.Name, subProp.GetValue(joinedObjectItem, null));
            }
            else
            {
                //Handle duplicate names
            }
        }
    }

    return toReturn;
}

Usage:

List<Dictionary<string, object>> results = new List<Dictionary<string, object>>();
 foreach (var item in jn)
        results.Add(joinLinqObjectProperties(item));

int iCount = 1;
foreach (var item in results)
{
    Console.WriteLine(String.Format("Object {0}:", iCount));
    foreach (var prop in item)
    {
        Console.WriteLine(String.Format("\tProperty: {0} = {1}", prop.Key, prop.Value));
    }

    Console.WriteLine();
    iCount++;
}

Output:

Object 1:
    Property: ClientId = 7
    Property: ClientName = ACME Inc.
    Property: Jobs = 5
    Property: ClientAddress = Gypsy Ave
    Property: ClientState = KY

Object 2:
    Property: ClientId = 8
    Property: ClientName = JUST Inc.
    Property: Jobs = 25
    Property: ClientAddress = Dorky Rd
    Property: ClientState = NC

To convert a Dictionary to a dynamic type:

private static dynamic dictionaryToDynamic(Dictionary<string, object> dictionary)
{
    dynamic result = new ExpandoObject();
    var resAsIDic = result as IDictionary<string, object>;

    foreach (var key in dictionary.Keys)
        resAsIDic[key] = dictionary[key];

    return result;
}

https://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx

*Note: The ExpandoObject inherits from IDictionary<string, object>. You should be able to cast the dynamic object back to Dictionary<string, object> if you want/need

Upvotes: 1

Related Questions