无法在动态对象上找到属性或字段

时间:2014-10-21 17:48:21

标签: c# linq

我使用Dynamic Linq进行一些数据库查询,到目前为止它工作得非常好。我可以将字符串传递给Select以选择如下字段:

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

例如。当您传递字符串变量而不是硬编码字符串时,显然会出现这种情况。我现在遇到的问题是库使用IEnumerable而不是IEnumerable<T>,因为很明显,它直到运行时才能知道T。我正在使用它来选择数据并最终将其返回给客户端,它可以正常地传输原始数据,但现在我希望能够在返回数据之前进行更多处理,并且需要让查询运行数据库首先。我可以这样做:

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

这将使查询运行。但问题是,一旦我这样做了,似乎我再也不能使用动态linq了。例如,如果我做了这样的事情:

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

我现在收到System.Linq.Dynamic.ParseException消息No property of field 'Foo' exists in type 'Object'(注意:我可以在调试器中看到materializedResults确实具有所有预期的属性。)

因此在转换为List后,我可能会迭代它并修改一些值,我不能再查询它。

所以我的问题是,如何进行动态查询(使用select,group by,order by order作为字符串提供),实现结果然后实际处理这些结果?

我想也许如果我可以投射到实际类型而不是dynamic它可能会起作用,所以我尝试了这个:

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;

哪个很丑,需要我施展两次。第一次到dynamic所以我可以从第一个项目获得类型,然后再次到达那个类型。

2 个答案:

答案 0 :(得分:1)

如果您执行YourStuff.Cast<dynamic>.ToList(),则会收到IEnumerable<object>,且Foo类型上没有属性object

你可能会问的问题,你怎么能得到IList<TheActualType>?!你可以这样做:

// 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;
    }

这是一个简单的扩展方法,可以在以后使用,如下:

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

答案 1 :(得分:0)

你的演员证明违约会导致错误

(output as System.Collections.Generics.IEnumerable)

此演员指定正确的界面再试一次

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