简体   繁体   中英

Can't find property or field on a dynamic object

I using Dynamic Linq to do some database queries and it's working really well up to now. I can pass a string to a Select to select fields like so:

var output = myDatabaseTable.Select("Foo, Bar");

For example. The power obviously being when you pass a string variable rather than hardcoded strings. The problem I'm running into now is that the library using IEnumerable instead of IEnumerable<T> because, obviously, it can't know T until runtime. I'm using this to select data and eventually return it to a client and it works fine for spitting out raw data, but now I want to be able to do some more processing before returning the data and that requires getting the query to run on the database first. I can do something like this:

var materializedResults = output.Cast<dynamic>().ToList();

And that will make the query run. But the problem is, once I've done that, it seems I can't use dynamic linq anymore. For example, if I did something like this:

var foos = materializedResults.Select("Foo");

I now get a System.Linq.Dynamic.ParseException with the message No property of field 'Foo' exists in type 'Object' (Note: I can see in the debugger that the materializedResults does actually have all the expected properties).

So after casting to a List so I can potentially iterate through it and modify some of the values, I can no longer query it.

So my question is, how can I take a dynamic query (with select, group by, order by etc provided as strings), materialize the results and then actually process those result dynamically?

I thought maybe if I could cast to the actual type rather than dynamic it might work, so I tried this:

var d = output.Cast<dynamic>().ToList();
MethodInfo method = typeof(Enumerable).GetMethod("Cast", new[] {typeof(IEnumerable)});
method = method.MakeGenericMethod(d.First().GetType());
output = method.Invoke(d, new[] {d}) as IEnumerable;

Which is ugly and requires me to cast twice. The first time to dynamic so I can get the type from the first item then again to that type.

If you do YourStuff.Cast<dynamic>.ToList() , you will receive IEnumerable<object> , and there is no property Foo on the type object .

The question you might be asking, how can you get IList<TheActualType> ?! You can do it this way:

// for IEnumerable
public static IList ToAnonymousList(this IEnumerable enumerable)
{
    var enumerator = enumerable.GetEnumerator();
    if (!enumerator.MoveNext())
        throw new Exception("?? No elements??");

    var value = enumerator.Current;
    var returnList = (IList) typeof (List<>)
        .MakeGenericType(value.GetType())
        .GetConstructor(Type.EmptyTypes)
        .Invoke(null);

    returnList.Add(value);

    while (enumerator.MoveNext())
        returnList.Add(enumerator.Current);

    return returnList;
}

    // for IQueryable
    public static IList ToAnonymousList(this IQueryable source)
    {
        if (source == null) throw new ArgumentNullException("source");

        var returnList = (IList) typeof (List<>)
            .MakeGenericType(source.ElementType)
            .GetConstructor(Type.EmptyTypes)
            .Invoke(null);

        foreach (var elem in source)
            returnList.Add(elem);

        return returnList;
    }

It's a simple extension method that can later be used, as such:

var test = (new[]
{
    new
    {
        Property1 = "10",
        Property2 = "10",
        Property3 = 1
    }
}
.Select("New(Property1, Property2)"))
.ToAnonymousList();

Your Cast is Defaulting to which will cause an error

(output as System.Collections.Generics.IEnumerable)

This Cast Specified the Correct Interface Try again

(output as System.Collections.IEnumerable).Cast<dynamic>().ToList()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM