我正在使用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>
当我希望我可以通过我的Where扩展名传递IEnumerable<MyListObjectType>
....
然后我在运行时遇到异常:
System.ArgumentException:'TOId'不是'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?)
答案 0 :(得分:1)
您需要动态访问它,但您可以使用'dynamic'关键字避免一些令人头疼的反思。
所以这个:
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();
}
}
答案 1 :(得分:0)
在您的第一个示例中,NewValueSubCollection
静态类型为IEnumerable<object>
,因此您的参数化类型T
为object
,当您编译表达式时,它会尝试查找对象类的属性,因此是异常。
同样地,o.Where(...)
无法正常工作,因为在Where
上定义了IEnumerable<>
扩展方法,并且这些方法在编译时是静态解析的。
我担心你必须通过反思来调用Where
方法,你可以在这里找到一些帮助:How do I invoke an extension method using reflection?