0

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.

Krishna
  • 347
  • 1
  • 6
  • 23

1 Answers1

1

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

Alan
  • 106
  • 7
  • Thanks for the answer Alan. Is there a way where i can retain the jn as anonymous type so i can convert that into List rather than dictionary. I have extension method to convert anonymous list into strong typed. I dont want to lose capability of accessing values using property names . – Krishna Jun 26 '16 at 02:44
  • Gotcha. The variable jn is an enumeration of an anonymous type (select new {i, j}) that contains 2 anonymous types (i and j). It's not possible to create anonymous types at run-time; they are created at compile-time. I'll update my answer to include information about the ExpandoObject class. – Alan Jun 26 '16 at 03:01
  • Thank for the update.i took the liberty to extended your first method itself to return Expando object rather than writing another extension method to convert to dynamic. The next hurdle i got is since this is dynamic object how do i access properties with in the dynamic object so i can convert to.strong type. my previous extension method choked out on reading property names using reflection. I can post the method i extended if you like to see what i did. – Krishna Jun 26 '16 at 03:33
  • What are you trying to accomplish? Why won't a Dictionary work? I'm missing context. If you really need to use reflection on a dynamic object, this post might help: http://stackoverflow.com/questions/2634858/how-do-i-reflect-over-the-members-of-dynamic-object. I'm starting to think you should ask "should I" instead of "can I". It's easy to go down the rabbit hole... – Alan Jun 26 '16 at 03:44
  • You can access values by property names with a Dictionary. – Alan Jun 26 '16 at 03:49
  • I'm trying to merge objects from 2 differnet sources into one using a key and then try to return IEnumerable to the front end to map the object to grid or show individual values in various controls to the user. – Krishna Jun 26 '16 at 03:54
  • List> (from my answer under Usage) is an IEnumerable. Sorry, but I don't see the problem here. – Alan Jun 26 '16 at 03:58
  • So Lets say my T is ClientInfo, can i use List> as List to access values using properties from ClientInfo? – Krishna Jun 26 '16 at 04:01
  • You'd have to initialize the ClientInfo object. Ex... var ci = new ClientInfo(); ci.prop1 = (CAST TYPE)dic["prop1"];. Alternatively, you could add a constructor to ClientInfo that takes a Dictionary parameter and initialize the values there. – Alan Jun 26 '16 at 04:08
  • Thank you for the help. Really appreciate it for taking time to explain – Krishna Jun 26 '16 at 04:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/115668/discussion-between-alan-and-user2344145). – Alan Jun 27 '16 at 01:25