1

我正在使用 JSON 编写 C# MVC 应用程序,并尝试使用 EF 将 JSON 检索回数据库。

不幸的是,我不会让这样的代码工作:

IEnumerable<object> NewValueSubCollection = (IEnumerable<object>)NewValue.GetType().GetProperty(col.Name).GetValue(NewValue, null);
//Where col is a property of an object of type (IEnumerable<???>)

foreach (var line in ((IEnumerable<object>)col.GetValue(originalEntity, null)).ToList<object>())
{
    Type lineType = ObjectContext.GetObjectType(line.GetType());
    var lineEntitySet = context.GetEntitySet(lineType);
    EntityKey lineKey = context.CreateEntityKey(lineEntitySet.Name, line);
    if (NewValueSubCollection.Where(lineKey).Count() == 0) //See bellow
    context.DeleteObject(line);
}

我在哪里实现了这个:

public static class LinqExtension
{
    //Enable searching in a collection is an entity Key exist... and retrieve info.
    public static IEnumerable<T> Where<T>(this IEnumerable<T> source,EntityKey key)
    {
        return Enumerable.Where(source, CreateFilterExpressionBasedOnKey<T>(key).Compile());
    }

    private static Expression<Func<TInput, bool>> CreateFilterExpressionBasedOnKey<TInput>(Type sourceType, EntityKey key)
    {
        var param = Expression.Parameter(sourceType, "");

        Expression myFilter = Expression.Constant(true);
        if (key != null)
        {
            foreach (var item in key.EntityKeyValues)
            {
                Expression Left = Expression.PropertyOrField(param, item.Key.ToString());
                Expression Right = Expression.Constant(item.Value);

                myFilter = Expression.AndAlso(myFilter, Expression.Equal(Left, Right));
            }
        }
        return Expression.Lambda<Func<TInput, bool>>(myFilter, param);
    }
}

问题是 NewValueSubCollection 的类型是:IEnumerable<object>当我希望我可以IEnumerable<MyListObjectType>通过我的 Where 扩展时……。然后我在运行时遇到了一个异常: System.ArgumentException: 'TOId' is not a member of type 'System.Object'

如果我使用:

Type generic = typeof(Collection<>);
Type typeArgs = (NewValue.GetType().GetProperty(col.Name).GetValue(NewValue, null)).GetType().GetGenericArguments()[0];
Type constructed = generic.MakeGenericType(typeArgs);
object o = Activator.CreateInstance(constructed);
o = NewValue.GetType().GetProperty(col.Name).GetValue(NewValue, null);

我收到以下代码的编译错误:

if (o.Where(lineKey).Count() == 0) //error!!!
// 'object' does not contain a definition for 'Where' acception a first argument of type 'object' could be found (are you missing directive or an assembly reference?)
4

2 回答 2

1

您需要动态访问它,但您可以使用“动态”关键字避免一些令人头疼的反射。

所以这:

NewValueSubCollection.Where(lineKey).Count() == 0

变成这样:

NewValueSubCollection.Cast<dynamic>().Where(d => lineKey(d)).Count() == 0

或者(更简单,更有效,如果枚举没有副作用)这个:

!NewValueSubCollection.Cast<dynamic>().Any(d => lineKey(d))

一个简单的概念证明程序:

class Program
{
    static void Main(string[] args)
    {
        var list = new List<string>();
        IEnumerable<object> objects = list;
        Func<string, bool> func = s => s.Contains("x");

        list.Add("Test");
        list.Add("x");
        list.Add("mux");
        foreach (var item in objects.Cast<dynamic>().Where(d => func(d)))
            Console.WriteLine(item);
        Console.ReadKey();
    }
}
于 2012-08-01T22:54:29.630 回答
0

在您的第一个示例中,您NewValueSubCollection的静态类型为IEnumerable<object>,因此您的参数化类型Tobject,并且当您编译表达式时,它会尝试查找对象类的属性,因此是异常。

同样,您o.Where(...)无法工作,因为Where扩展方法是在 上定义的IEnumerable<>,并且这些方法是在编译时静态解析的。

恐怕您必须Where通过反射调用该方法,您可能会在这里找到一些帮助:如何使用反射调用扩展方法?

于 2012-08-01T21:46:23.783 回答