可以';在动态对象上找不到属性或字段

本文关键字:找不到 属性 字段 对象 动态 可以 | 更新日期: 2023-09-27 18:27:17

我使用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、groupby、orderby等),实现结果,然后实际动态处理这些结果?

我想如果我可以转换为实际类型而不是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,这样我就可以从第一个项目中获得类型,然后再到那个类型。

可以';在动态对象上找不到属性或字段

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

你可能会问的问题是,你如何获得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();

您的角色默认为将导致错误

(output as System.Collections.Generics.IEnumerable)

此强制转换指定了正确的接口重试

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