- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
首先我要说的是,我是菜鸟,我不知道自己在做什么。因此,如果有更好的方法可以做到这一点,我会洗耳恭听。
目前,我正在开发一个项目,我需要能够将数据源强制转换为 List<T>
,其中T
是匿名类型,并使用 lambda 表达式对其进行过滤,或者动态创建 lambda 表达式,将它们保存到数据库中。我已经为 System.Linq.Dynamic.Core
创建了一个静态包装类,称为 RunTimeType
,它具有允许我从某些数据源创建匿名类型的方法,然后创建 List<>
那种匿名类型。在anontype
之后和List<anontype>
创建后,我正在使用 existing fluent interface创建 Expression<Func<T, bool>>
。一旦我构建了 Expression
并编译它,我要么想执行它,要么想将它转换为字符串并保存到数据库、xml文件等中,以供以后使用。
情况1:
当编译然后立即执行表达式时,直到这一行我都很好:
var testList = anonList.Where(castedExp).ToList();
我收到以下错误:
Error CS1973 C# has no applicable method named 'Where' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.
这是有道理的,因为 filter
被声明为 dynamic
,我被迫这样做,否则编译器会提示以下内容:
Error CS1061 'object' does not contain a definition for 'By' and no accessible extension method 'By' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
情况2:
对于构建表达式的情况,将其转换为字符串,然后编译为有效的 Func<T,TResult>
,直到这一行我都很好:
var castedExp = (Func<dynamic, bool>)compileExp;
我收到以下错误:
Error System.InvalidCastException 'System.Func
2[<>f__AnonymousType0
2[System.String,System.String],System.Boolean]' to type 'System.Func`2[System.Object,System.Boolean]'.'
但是,我知道如果我不明确转换为 Func<dynamic, bool>
,编译器将提示以下内容:
Error CS1503
Argument 2: cannot convert from 'System.Delegate' to 'System.Func<dynamic, bool>'
.
所以,我的问题是,如何解决这两种情况,同时仍然保持使用匿名类型的能力。只是为了再次澄清,我被迫创建一个匿名类型,因为我不知道在运行时将获得什么数据集,因为这些数据集是完全动态的。
我想重申,只要满足项目的限制,我愿意以不同的方式做到这一点。坦白说,我已经在这方面工作了一段时间,我没有想法,我需要一些指导。
下面是所有相关代码。
测试代码:
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using ExpressionBuilder.Generics;
using ExpressionBuilder.Common;
using System.Linq;
using System.Linq.Dynamic;
using System.Linq.Dynamic.Core;
using ExpressionBuilterTest.TestImplementations;
namespace ExpressionBuilterTest
{
class Program
{
static void Main(string[] args)
{
//test Data source
object[,] arrayTest = new object[3, 2];
arrayTest[0, 0] = "Field1";
arrayTest[1, 0] = "X1";
arrayTest[2, 0] = "Y1";
arrayTest[0, 1] = "Field2";
arrayTest[1, 1] = "X2";
arrayTest[2, 1] = "Y2";
var anonType = RunTimeType.Create(arrayTest);
var anonList = RunTimeType.CreateGenericList(anonType, arrayTest);
//Creation of List<anonymous> type
var anonList = CreateGenericList(anonType, arrayTest);
//Creation of List<anonymous> type
Type genericFilter = typeof(Filter<>);
Type constructedClass = genericFilter.MakeGenericType(anonType);
//*************************Case 1*************************
/*
use dynamic otherwise compiler complains about accessing
methods on the instance of the filter object
*/
dynamic filter = Activator.CreateInstance(constructedClass);
filter.By("Field1", Operation.Contains, " X1 ")
.Or.By("Field2", Operation.Contains, " X2 ");
//returns Expression<Func<T, bool>>
var lamda = filter.GetExpression();
//Error CS1973
IEnumerable<dynamic> testList = anonList.Where(castedExp).ToList();
Console.WriteLine(testList.Count().ToString());
Console.WriteLine("\n");
//*************************Case 2*************************
//convert to string
string expString = lamda.Body.ToString().Replace("AndAlso", "&&").Replace("OrElse", "||");
// simulation of compiling an expression from a string which would be returned from a database
var param = Expression.Parameter(anonType, ExpressionParameterName.Parent);
var exp = System.Linq.Dynamic.DynamicExpression.ParseLambda(new ParameterExpression[] { param }, typeof(bool), expString);
var compiledExp = exp.Compile();
//*******************************************************
//Error CS1973
'System.Func`2[<>f__AnonymousType0`2[System.String,System.String],System.Boolean]' to type 'System.Func`2[System.Object,System.Boolean]'.'
var castedExp = (Func<dynamic, bool>)compileExp;
//*******************************************************
var testList2 = anonList.Where(castedExp).ToList();
Console.WriteLine(testList2.Count().ToString());
Console.ReadKey();
}
}
}
RunTimeType 类:
(为了简洁起见,我省略了 Create
和 CreateGenericList
方法的重载)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Runtime.CompilerServices;
namespace ExpressionBuilterTest.TestImplementations
{
public static class RunTimeType
{
/// <summary>
/// Creates an anonymous type from a 2d array that includes headers
/// </summary>
public static Type Create<T>(T[,] fieldNameAndValues)
{
IList<System.Linq.Dynamic.Core.DynamicProperty> properties = new List<System.Linq.Dynamic.Core.DynamicProperty>();
int columnCount = fieldNameAndValues.GetLength(1);
for (int jj = 0; jj < columnCount; jj++)
properties.Add(new System.Linq.Dynamic.Core.DynamicProperty(fieldNameAndValues[0, jj].ToString(), fieldNameAndValues[1, jj].GetType()));
return DynamicClassFactory.CreateType(properties);
}
/// <summary>
/// Creates an IEnumerable<dynamic>, where dynamic is an anonymous type, from a 2d array
/// </summary>
/// <param name="type">Anonymous type</param>
/// <param name="data">2 dimensional array of data</param>
public static IEnumerable<dynamic> CreateGenericList<T>(Type anonType, T[,] data)
{
ThrowIfNotAnonymousType(anonType);
dynamic dynoObject = Activator.CreateInstance(anonType);
var fieldNames = dynoObject.GetDynamicMemberNames();
Type genericListType = typeof(List<>);
Type constructedClass = genericListType.MakeGenericType(anonType);
dynamic list = (IEnumerable<dynamic>)Activator.CreateInstance(constructedClass);
int rowCount = data.GetLength(0);
int jj;
for (int ii = 1; ii < rowCount; ii++) //skip first row
{
jj = 0;
foreach (var field in fieldNames)
anonType.GetProperty(field).SetValue(dynoObject, data[ii, jj], null);
jj++;
list.Add(dynoObject);
}
return list;
}
private static void ThrowIfNotAnonymousType(Type type)
{
if (!IsAnonymousType(type))
throw new Exception("'anonType' must be an anonymous type");
}
//https://stackoverflow.com/questions/1650681/determining-whether-a-type-is-an-anonymous-type
private static Boolean IsAnonymousType(Type type)
{
Boolean hasCompilerGeneratedAttribute = type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Count() > 0;
Boolean nameContainsAnonymousType = type.FullName.Contains("AnonymousType");
Boolean isAnonymousType = hasCompilerGeneratedAttribute && nameContainsAnonymousType;
return isAnonymousType;
}
}
}
更新:
我合并了 @CSharpie 的答案,并对其进行了定制以适合我的实现。一切都会编译,但是,我没有得到正确的输出(请参阅代码正文中的注释)。
static void Main(string[] args)
{
object[,] arrayTest = new object[3, 2];
arrayTest[0, 0] = "Field1";
arrayTest[1, 0] = "X1";
arrayTest[2, 0] = "Y1";
arrayTest[0, 1] = "Field2";
arrayTest[1, 1] = "X2";
arrayTest[2, 1] = "Y2";
var anonType = RunTimeType.Create(arrayTest);
var anonList = RunTimeType.CreateGenericList(anonType, arrayTest);
Type targetType = anonType;
Type genericFilter = typeof(Filter<>);
Type constructedClass = genericFilter.MakeGenericType(targetType);
dynamic filter = Activator.CreateInstance(constructedClass);
//Dynamically build expression
filter.By("Field1", Operation.Contains, "X")
.Or.By("Field2", Operation.Contains, "2");
//Returns Expression<Func<anonType, bool>>
var lamda = filter.GetExpression();
string expString = lamda.Body.ToString();
expString = expString.Replace("AndAlso", "&&").Replace("OrElse", "||");
/*
Prints: (((x.Field1 != null) && x.Field1.Trim().ToLower().Contains("X".Trim().ToLower())) || ((x.Field2 != null) &&
x.Field2.Trim().ToLower().Contains("2".Trim().ToLower())))
*/
Console.WriteLine(expString);
ParameterExpression param = Expression.Parameter(targetType, ExpressionParameterName.Parent);
LambdaExpression exp = System.Linq.Dynamic.DynamicExpression.ParseLambda(new ParameterExpression[] { param }, typeof(bool), expString);
Delegate compileExp = exp.Compile();
MethodInfo whereMethod = typeof(Enumerable).GetMethods().Single(m =>
{
if (m.Name != "Where" || !m.IsStatic)
return false;
ParameterInfo[] parameters = m.GetParameters();
return parameters.Length == 2 && parameters[1].ParameterType.GetGenericArguments().Length == 2;
});
MethodInfo finalMethod = whereMethod.MakeGenericMethod(anonType);
IEnumerable resultList = (IEnumerable)finalMethod.Invoke(null, new object[] { anonList, compileExp });
/*
Prints Nothing but should print the following:
X1 X2
*/
foreach (dynamic val in resultList)
{
Console.WriteLine(val.Field1 + "/t" + val.Field2);
}
Console.ReadKey();
}
最终更新:
对于那些感兴趣的人,我终于成功了。我发现我的CreateGenericList
方法,仅返回我的匿名类型的第一个实例的列表。这么说CreateGenericList
应该变成:
/// <summary>
/// Creates an IEnumerable<dynamic>, where dynamic is an anonymous type, from a 2d array
/// </summary>
/// <param name="type">Anonymous type</param>
/// <param name="data">2 dimensional array of data</param>
public static IEnumerable<dynamic> CreateGenericList<T>(Type anonType, T[,] data)
{
ThrowIfNotAnonymousType(anonType);
Type genericListType = typeof(List<>);
Type constructedClass = genericListType.MakeGenericType(anonType);
dynamic list = (IEnumerable<dynamic>)Activator.CreateInstance(constructedClass);
//first instance
dynamic dynoObject = Activator.CreateInstance(anonType);
//System.Linq.Dynamic.Core.DynamicClass.GetDynamicMemberNames()
var fieldNames = dynoObject.GetDynamicMemberNames();
int rowCount = data.GetLength(0);
int jj;
for (int ii = 1; ii < rowCount; ii++) //skip first row
{
jj = 0;
foreach (var field in fieldNames)
{
//System.Linq.Dynamic.Core.DynamicClass.SetDynamicPropertyValue()
dynoObject.SetDynamicPropertyValue(field,data[ii, jj]);
jj++;
}
list.Add(dynoObject);
//create a new instance for each iteration of the loop
dynoObject = Activator.CreateInstance(anonType);
}
return list;
}
然后Main
变成:
static void Main(string[] args)
{
object[,] arrayTest = new object[3, 2];
arrayTest[0, 0] = "Field1";
arrayTest[1, 0] = "X1";
arrayTest[2, 0] = "blah";
arrayTest[0, 1] = "Field2";
arrayTest[1, 1] = "Y1";
arrayTest[2, 1] = "Y2";
var anonType = RunTimeType.Create(arrayTest);
var anonList = RunTimeType.CreateGenericList(anonType, arrayTest);
Type genericFilter = typeof(Filter<>);
Type constructedClass = genericFilter.MakeGenericType(anonType);
dynamic filter = Activator.CreateInstance(constructedClass);
//Dynamically build expression
filter.By("Field1", Operation.Contains, "blah")
.Or.By("Field2", Operation.Contains, "2");
//Returns Expression<Func<anonType, bool>>
var lamda = filter.GetExpression();
//Prints: System.Func`2[<>f__AnonymousType0`2[System.String,System.String],System.Boolean]
Console.WriteLine(lamda.Compile().ToString());
Console.WriteLine("\n");
string expBodyString = lamda.Body.ToString();
/*
Prints: (((x.Field1 != null) AndAlso x.Field1.Trim().ToLower().Contains("blah".Trim().ToLower()))
OrElse ((x.Field2 != null) AndAlso x.Field2.Trim().ToLower().Contains("2".Trim().ToLower())))
*/
Console.WriteLine(expBodyString);
Console.WriteLine("\n");
expBodyString = expBodyString.Replace("AndAlso", "&&").Replace("OrElse", "||");
/*
Prints: (((x.Field1 != null) && x.Field1.Trim().ToLower().Contains("blah".Trim().ToLower())) || ((x.Field2 != null)
&& x.Field2.Trim().ToLower().Contains("2".Trim().ToLower())))
*/
Console.WriteLine(expBodyString);
Console.WriteLine("\n");
ParameterExpression param = Expression.Parameter(anonType, ExpressionParameterName.Parent);
LambdaExpression exp = System.Linq.Dynamic.Core.DynamicExpressionParser.ParseLambda(new ParameterExpression[] { param }, typeof(bool), expBodyString);
/*
Prints: (((x.Field1 != null) AndAlso x.Field1.Trim().ToLower().Contains("blah".Trim().ToLower()))
OrElse ((x.Field2 != null) AndAlso x.Field2.Trim().ToLower().Contains("2".Trim().ToLower())))
*/
Console.WriteLine(exp.Body.ToString());
Console.WriteLine("\n");
Delegate compileExp = exp.Compile();
//Prints: System.Func`2[<>f__AnonymousType0`2[System.String,System.String],System.Boolean]
Console.WriteLine(compileExp.ToString());
Console.WriteLine("\n");
MethodInfo whereMethod = typeof(Enumerable).GetMethods().Single(m =>
{
if (m.Name != "Where" || !m.IsStatic)
return false;
ParameterInfo[] parameters = m.GetParameters();
return parameters.Length == 2 && parameters[1].ParameterType.GetGenericArguments().Length == 2;
});
MethodInfo finalMethod = whereMethod.MakeGenericMethod(anonType);
IEnumerable resultList = (IEnumerable)finalMethod.Invoke(null, new object[] { anonList, compileExp });
//Prints: blah Y2
foreach (dynamic val in resultList)
{
Console.WriteLine(val.Field1 + "\t" + val.Field2);
}
Console.ReadKey();
}
最佳答案
这是一个简单的示例,没有任何额外的 nuget 包,调用 Enumerable.Where
方法。我不知道您到底使用什么软件包,因此您必须根据您的要求进行调整。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
public class Program
{
static void Main(string[] args)
{
var test = new {Foo = "bar"};
var test2 = new {Foo = "derp"};
// get the annonymous type
Type anonType = test.GetType();
// create a list of that annonymous type
IList genericList = (IList) Activator.CreateInstance(typeof(List<>).MakeGenericType(anonType));
genericList.Add(test);
genericList.Add(test2);
// Find the correct Enumerable.Where method
MethodInfo whereMethod = typeof(Enumerable).GetMethods().Single(m =>
{
if (m.Name != "Where" || !m.IsStatic)
return false;
ParameterInfo[] parameters = m.GetParameters();
return parameters.Length == 2 && parameters[1].ParameterType.GetGenericArguments().Length == 2;
});
// construct the finalmethod using generic type
MethodInfo finalMethod = whereMethod.MakeGenericMethod(anonType);
// define the Type of the Filter Func<anontype,bool>
Type filterType = typeof(Func<,>).MakeGenericType(anonType, typeof(bool));
// Build a simple filter expression
// this is mostly to subsitute for the missing packages you are using to create that filter func
ParameterExpression parameter = Expression.Parameter(anonType, "item");
MemberExpression member = Expression.Property(parameter, "Foo");
BinaryExpression euqalExpression = Expression.Equal(member, Expression.Constant("derp"));
LambdaExpression filterExpression = Expression.Lambda(filterType, euqalExpression, parameter);
Delegate filter = filterExpression.Compile();
Console.WriteLine("This is the Filter: {0}", filterExpression);
// Finally invoke and see it in action
IEnumerable result = (IEnumerable) finalMethod.Invoke(null, new object[] {genericList, filter});
foreach (dynamic o in result)
{
Console.WriteLine(o.Foo);
}
Console.ReadKey();
}
}
这里的问题是,您需要自己构造泛型方法,这意味着您必须提供泛型参数。在你的情况下它是 anonType。这就是这条线正在做的事情
MethodInfo finalMethod = whereMethod.MakeGenericMethod(anonType);
之后,我使用 System.Linq.Expressions 创建一个简单的 Func<anontype, bool>
它代表过滤器。
更新
这对我现在有用,缺陷一定是你正在做的其他事情。我把这个问题留给你去解决。
object[,] arrayTest = new object[3, 2];
arrayTest[0, 0] = "Field1";
arrayTest[1, 0] = "X1";
arrayTest[2, 0] = "derp";
arrayTest[0, 1] = "Field2";
arrayTest[1, 1] = "X2";
arrayTest[2, 1] = "Y2";
var anonType = RunTimeType.Create(arrayTest);
var anonList = ( IList)RunTimeType.CreateGenericList(anonType, arrayTest);
// define the Type of the Filter Func<anontype,bool>
Type filterType = typeof(Func<,>).MakeGenericType(anonType, typeof(bool));
// Build a simple filter expression
ParameterExpression parameter = Expression.Parameter(anonType, "item");
var property = anonType.GetProperty("Field1");
MemberExpression member = Expression.Property(parameter, property);
BinaryExpression euqalExpression = Expression.Equal(member, Expression.Constant("derp"));
MethodInfo whereMethod = typeof(Enumerable).GetMethods().Single(m =>
{
if (m.Name != "Where" || !m.IsStatic)
return false;
ParameterInfo[] parameters = m.GetParameters();
return parameters.Length == 2 && parameters[1].ParameterType.GetGenericArguments().Length == 2;
});
MethodInfo finalMethod = whereMethod.MakeGenericMethod(anonType);
LambdaExpression filterExpression = Expression.Lambda(filterType, euqalExpression, parameter);
Delegate filter = filterExpression.Compile();
Console.WriteLine("This is the Filter: {0}", filterExpression);
IEnumerable result = (IEnumerable) finalMethod.Invoke(null, new object[] {anonList, filter});
foreach (dynamic o in result)
{
Console.WriteLine(o.Field1);
}
Console.ReadKey();
关于c# - 如何处理匿名类型 <T> 的强制转换委托(delegate),委托(delegate) T 以便在 IEnumerable<T> 的Where<T>() 方法中使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59594284/
任何人都可以向我解释 IEnumerable 和 IEnumerator 之间的区别是什么, 以及如何使用它们? 谢谢!!! 最佳答案 通常,一个 IEnumerable是可以枚举的对象,例如列表或数
function TSomething.Concat(const E: IEnumerable>): IEnumerable; begin Result := TConcatIterator.Cr
我正试图找到解决这个问题的办法: 给定一个 IEnumerable> 我需要一个返回输入的方法/算法,但是如果多个 IEnumerable 具有相同的元素,则每个巧合/组只返回一个。 例如 I
我有一个有趣的问题:给定一个 IEnumerable , 是否有可能产生 IEnumerable> 的序列一次将相同的相邻字符串分组? 让我解释一下。 1。基本说明示例: 考虑以下 IEnumerab
我有课 public class Test { public void M1(IEnumerable> p) { } public void M2(IEnumerable)> p) {
我尝试解决下一个练习: 输入:整数列表 count >= 1;一些正整数 k 输出:此整数的所有可能元组,长度为 k ; 例如 输入: {1, 2}; k = 4 输出: { {1, 1, 1, 1
抱歉奇怪的标题。我想要实现的目标很简单: IEnumerable> listoflist; IEnumerable combined = listoflist.CombineStuff(); 例子:
公共(public)类项目 { ... public class Order { public List Items ... } public class Customer {
我有一个 IEnumerable>我想转换为单一维度集合的集合。是否可以使用通用扩展方法来实现这一点?现在我正在这样做以实现它。 List filteredCombinations = new Lis
我有一个 IEnumerable> CustomObject在哪里有一个 x (用作键(在本例中为 1 、 2 、 3 ))和 y值(value)。一些假数据: { { {1, 2}, {2, 4
我需要做的是选择嵌套元素列表,这是我的查询 returns IEnumerable>这是我的 linq 表达式: from a in (questions.Select(x => x.AnswerLi
如何使用 LINQ(或其他方式)将 IEnumerables 的 IEnumerable 拆分为一个平面 IEnumerable? 最佳答案 enumerable.SelectMany(x => x)
例如: public interface IEnumerable { IEnumerator GetEnumerator(); } //This interface allows the c
我对 Reflection.Emit 有疑问。我想要动态创建的类,它具有 ICollection 的简单实现。我定义的所有方法都很好,而不是接下来的两个: public IEnumerator Get
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: Why was IEnumerable made covariant in C# 4? 我正在查看 MSDN
IEnumerator.MoveNext() 的实现是否预计会相对较快?或者如果“移动到下一项” 包括磁盘 IO、Web 请求或其他可能长时间运行的操作是否可以? 例如,我正在处理一个处理文档的项目,
以下代码创建了 List 的中间实例并在 yield 返回之前将值附加到它。有没有一种好的方法可以避免创建实例并直接 yield 返回单元格值? IEnumerable> GetStrValues()
我有两个 IEnumerable 对象,我想验证其中一个是否包含另一个的所有元素。 我正在使用 obj1.Intersect(obj2).Any() 但交集没有像我预期的那样工作。即使 obj2 中只
我正在尝试这个 MSDN page 上的例子.我试图更改 GetEnumerator 方法。我知道那似乎有些不对劲,但它符合要求然后就不会运行。错误是枚举器尚未启动,应该调用 MoveNext,但 它
我写过关于自定义 IEnumerator 的文章。从中生成 IEnumerable 的最简单方法是什么?理想的解决方案(一行代码)是是否有一些用于该目的的类。还是我必须自己创建? 最佳答案 不幸的是,
我是一名优秀的程序员,十分优秀!