HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Finding elements inside ExpandoObject

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
insideexpandoobjectelementsfinding

Problem

Is it possible to simplify the code below?

dynamic model = GetExpandoObject(); //model type of ExpandoObject

var result = model.FirstOrDefault(x => x.Key == "node").Value;

if (result != null)
{
    result = ((ExpandoObject)result).FirstOrDefault(x => x.Key == "children");

    if (result != null)
    {
        result = ((IList)((KeyValuePair)result).Value).FirstOrDefault();

        if (result != null)
        {
            if (result != null)
            {
                result = ((ExpandoObject)result).FirstOrDefault(x => x.Key == "node").Value;

                if (result != null)
                {
                    result = ((ExpandoObject)result).FirstOrDefault(x => x.Key == "stuff");
                }
            }
        }
    }
}


Maybe it is possible to implement similar logic with Linq? Any thoughts?

Solution

In your code, the variable result is just of type object because the compiler doesn't know what the result of FirstOrDefault is going to be.

Below I've used explicit typing using T for clarity and so that var doesn't evaluate to object

I created this extension method so that you wouldn't have to cast the object everytime you wanted to use it... this takes care of that before it returns

public static class ExtensionMethods
{
    public static T FirstOrDefault(this ExpandoObject eo, string key)
    {
        object r = eo.FirstOrDefault(x => x.Key == key).Value;
        return (r is T) ? (T)r : default(T);
    }
}


What follows is a re-implementation of the original post's code using the above method

ExpandoObject model = GetExpandoObject();

var someExpandoObject = model.FirstOrDefault("node");
if (someExpandoObject == null) return;

var kvp = someExpandoObject.FirstOrDefault>("children");
if (kvp.Equals(default(KeyValuePair))) return;

var ilo = kvp.Value as IList;
if (ilo == null) return;

someExpandoObject = ilo.FirstOrDefault() as ExpandoObject;
if (someExpandoObject == null) return;

someExpandoObject = someExpandoObject.FirstOrDefault("node");
if (someExpandoObject == null) return;

object finalResult = someExpandoObject.FirstOrDefault("stuff");


What follows is another possible implementation using nested if statements instead of multiple return statements.

ExpandoObject model = GetExpandoObject();

ExpandoObject someExpandoObject;
KeyValuePair kvp;
IList ilo;
object finalResult;

if ((someExpandoObject = model.FirstOrDefault("node")) != null)
{
    if (!(kvp = someExpandoObject.FirstOrDefault>("children")).Equals(default(KeyValuePair)))
    {
        if ((ilo = kvp.Value as IList) != null)
        {
            if ((someExpandoObject = ilo.FirstOrDefault() as ExpandoObject) != null)
            {
                if ((someExpandoObject = someExpandoObject.FirstOrDefault("node")) != null)
                    finalResult = someExpandoObject.FirstOrDefault("stuff");
            }
        }
    }
}


Update:
Using a newer feature of C# null-propagation, we can string all these calls together. Now we no longer need to save each object down the chain (unless we want to).

Here is an implementation using null-propagation.

object finalResult = ((model.FirstOrDefault("node")
    ?.FirstOrDefault>("children").Value as IList)
    ?.FirstOrDefault() as ExpandoObject)
    ?.FirstOrDefault("stuff");

Code Snippets

public static class ExtensionMethods
{
    public static T FirstOrDefault<T>(this ExpandoObject eo, string key)
    {
        object r = eo.FirstOrDefault(x => x.Key == key).Value;
        return (r is T) ? (T)r : default(T);
    }
}
ExpandoObject model = GetExpandoObject();

var someExpandoObject = model.FirstOrDefault<ExpandoObject>("node");
if (someExpandoObject == null) return;

var kvp = someExpandoObject.FirstOrDefault<KeyValuePair<string, object>>("children");
if (kvp.Equals(default(KeyValuePair<string, object>))) return;

var ilo = kvp.Value as IList<object>;
if (ilo == null) return;

someExpandoObject = ilo.FirstOrDefault() as ExpandoObject;
if (someExpandoObject == null) return;

someExpandoObject = someExpandoObject.FirstOrDefault<ExpandoObject>("node");
if (someExpandoObject == null) return;

object finalResult = someExpandoObject.FirstOrDefault<object>("stuff");
ExpandoObject model = GetExpandoObject();

ExpandoObject someExpandoObject;
KeyValuePair<string, object> kvp;
IList<object> ilo;
object finalResult;

if ((someExpandoObject = model.FirstOrDefault<ExpandoObject>("node")) != null)
{
    if (!(kvp = someExpandoObject.FirstOrDefault<KeyValuePair<string, object>>("children")).Equals(default(KeyValuePair<string, object>)))
    {
        if ((ilo = kvp.Value as IList<object>) != null)
        {
            if ((someExpandoObject = ilo.FirstOrDefault() as ExpandoObject) != null)
            {
                if ((someExpandoObject = someExpandoObject.FirstOrDefault<ExpandoObject>("node")) != null)
                    finalResult = someExpandoObject.FirstOrDefault<object>("stuff");
            }
        }
    }
}
object finalResult = ((model.FirstOrDefault<ExpandoObject>("node")
    ?.FirstOrDefault<KeyValuePair<string, object>>("children").Value as IList<object>)
    ?.FirstOrDefault() as ExpandoObject)
    ?.FirstOrDefault<object>("stuff");

Context

StackExchange Code Review Q#43400, answer score: 8

Revisions (0)

No revisions yet.