0

I'm trying to build a generic method to convert objects into ExpandoObjects and I can handle all cases except when one of the properties is an array.

    public static ExpandoObject ToExpando(this object AnonymousObject) {
        dynamic NewExpando = new ExpandoObject();
        foreach (var Property in AnonymousObject.GetType().GetProperties()) {
            dynamic Value;
            if (IsPrimitive(Property.PropertyType)) {
                Value = Property.GetValue(AnonymousObject);
            } else if (Property.PropertyType.IsArray) {
                dynamic ArrayProperty = new List<dynamic>();
                var ArrayElements = (Array)Property.GetValue(AnonymousObject);
                for (var i = 0; i < ArrayElements.Length; i++) {
                    var Element = ArrayElements.GetValue(i);
                    if (IsPrimitive(Element.GetType())) {
                        ArrayProperty.Add(Element);
                    } else {
                        ArrayProperty.Add(ToExpando(Element));
                    }
                }

                Value = ArrayProperty;//.ToArray();
            } else {
                Value = ToExpando(Property.GetValue(AnonymousObject));
            }
            ((IDictionary<string, object>) NewExpando)[Property.Name] = Value;
        }
        return NewExpando;
    }

    private static bool IsPrimitive(System.Type type) {
        while (type.IsGenericType && type.GetGenericTypeDefinition() == typeof (Nullable<>)) {
            // nullable type, check if the nested type is simple.
            type = type.GetGenericArguments()[0];
        }
        return type.IsPrimitive || type.IsEnum || type.Equals(typeof (string)) || type.Equals(typeof (decimal));
    }

Any property that's an array doesn't seem to be a dynamic object and when I use it on something like a razor template the array elements and properties aren't visible.

For example, if I do this:

var EmailParams = new {
            Parent = new {
                Username = "User1",
            },
            Students = new [] {new {Username = "Student1", Password = "Pass1"} }
        };

I get the following: VS Watch

As you can see the anonymous object at the top has an array of Students, but the converted ExpandoObject does not.

Does anyone have any insight on how I would change the code to add support for arrays/list in the ExpandoObject?

Thanks!

1

1 Answer 1

2

When you create an object like

var person = new
            {
                FirstName = "Test",
                LastName = new List<Person>() { new Person()
                {
                    FirstName = "Tes2"                    
                } }
            };

LastName is a generic list and Property.PropertyType.IsArray returns false on that case. So your "array/list" is not treated with this logic that you are trying to add

dynamic ArrayProperty = new List<dynamic>();
                var ArrayElements = (Array)Property.GetValue(AnonymousObject);
                for (var i = 0; i < ArrayElements.Length; i++) {
                    var Element = ArrayElements.GetValue(i);
                    if (IsPrimitive(Element.GetType())) {
                        ArrayProperty.Add(Element);
                    } else {
                        ArrayProperty.Add(ToExpando(Element));
                    }
                }

Hope this helps

Just one remark, you don't need to check again inside the logic of the if(Property.Property.Type.IsArray) the Primitive values, you did it, that is one of the stop conditions of your recursion. Below is the same code with the difference that I am mentioning

 public static ExpandoObject ToExpando(this object AnonymousObject)
        {
            dynamic NewExpando = new ExpandoObject();
            foreach (var Property in AnonymousObject.GetType().GetProperties())
            {
                dynamic Value;
                if (IsPrimitive(Property.PropertyType))
                {
                    Value = Property.GetValue(AnonymousObject);
                }
                else if (Property.PropertyType.IsArray)
                {
                    var ArrayProperty = new List<ExpandoObject>();
                    var elements = Property.GetValue(AnonymousObject) as IEnumerable;

                    //is the same as foreach all elements calling to Expando and adding them to elemenstArray
                    if (elements != null)
                        ArrayProperty.AddRange(from object elem in elements select ToExpando(elem));

                    Value = ArrayProperty;
                }
                else
                {
                    Value = ToExpando(Property.GetValue(AnonymousObject));
                }
                ((IDictionary<string, object>)NewExpando)[Property.Name] = Value;
            }
            return NewExpando;
        }
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your response Zinov. I'm actually calling .ToArray() explicitly on the list so that shouldn't be an issue. And while debugging I've confirmed that Property.PropertyType.IsArray is in fact true.
Can you put the input data of your example?
I've just added an example
Maybe you are confused, I run the code and clearly you have all Properties on the ExpandoObject. You are trying to visualize them through the DynamicView and that will get just the dynamic members for that object, the ResultView is the one that iterates over all members that are IEnumerable, try to expand ResultView and inside you will see your property with the list with all values. I am adding on my answer a comment about the particular code that process the Array

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.