- 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/
所以 promises 对我来说是相当新的,但我喜欢这个想法。 之前... 我以前用过这个,它只在文件被完全读取并按预期工作后才简单地返回数据: function something{ fo
当我尝试编译时出现以下错误: In member function 'double search::IDAstar::dfs(const State&, double)': 153:18: erro
最接近下面的是什么?不幸的是,下面的方法名称编译错误。 int val = delegate(string s) { return 1; }("test"); 我也尝试了 (...)=>{..
1、评论提交超时: 大家可能会发现,在提交评论非常缓慢时最容易出现“匿名”现象,这种情况主要是由于评论提交时执行时间过长引起的,可能是装了比较耗时的插件(比如Akismet等);很多博
我想在同一个表中使用一个键插入一个匿名表,如下所示: loadstring( [[return { a = "One", b = a.." two" }]] ) 在我看来,这应该返回下表: {
有人知道免费的匿名 smtp 服务吗?我想让我的应用程序的用户能够偶尔向我发送一封匿名电子邮件,而无需配置输入他们电子邮件帐户的服务器。我想我可以为此目的设置一个 gmail 帐户并将凭据嵌入到应用程
我有这个数据补丁: ALTER TABLE MY_TABLE ADD new_id number; DECLARE MAX_ID NUMBER; BEGIN SELECT max(id)
假设我有以下数据框。 Person_info (Bob, 2) (John, 1) (Bek, 10) (Bob, 6) 我想通过保持它们的值(value)来匿名。 Person_info (Pers
根据多个国家/地区的法律要求,我们在日志文件中匿名化用户的 IP 地址。使用 IPv4,我们通常只是匿名化最后两个字节,例如。而不是 255.255.255.255我们记录255.255.\*.\*
我正在学习有关 Scala 的更多信息,但在理解 http://www.scala-lang.org/node/135 中的匿名函数示例时遇到了一些麻烦。 .我复制了下面的整个代码块: object
我正在开设一个 Commerce 网上商店。 我想添加 Commerce 愿望 list ,但现在该模块仅适用于注册用户,因为未注册它不起作用。 我将显示 block 中的角色设置为匿名,但即使在更改
我正在使用发现的 Google Apps 脚本 here让匿名用户将文件上传到我的 Google 云端硬盘。 我想要的是脚本使用表单上输入的名称创建一个文件夹,然后将文件存放在该文件夹中。 到目前为止
我遇到的情况是,我正在等待一些事件的发生。我看到很多关于如何使用命名函数使用 setTimeout 的好例子,但是有没有办法使用某种匿名方法来设置超时? 代码目前看起来像这样: testForObje
我一直在阅读一些关于 Android 内存泄漏的文章,并观看了来自 Google I/O 的这个有趣的视频 on the subject . 尽管如此,我仍然不完全理解这个概念,尤其是当它对用户安全或
我正在尝试适应 Spring JDBC,但让我烦恼的是使用这些匿名类,我们不能传递任何局部变量,除非它们是最终的,这可能很容易安排,但是如果我需要循环一个怎么办?数组还是集合?我无法将“FedMode
我正在尝试将数据输入到 Oracle 数据库中。这将是一个带有多个参数的存储过程……我的意思是像 27 个参数(别问,我没有设计它)…… 现在我必须以某种方式填充此存储过程的参数...存储过程采用的大
我之前问过这个问题:Combine a PartialFunction with a regular function 然后意识到,我实际上并没有问对。 所以,这是另一个尝试。 如果我这样做: va
我想从 C++ 执行一个匿名的 Qt 脚本函数,但不知道要使用的 QScriptContext。 这是脚本: { otherObject.Text = "Hello World"; setTi
我有一个返回 promise 的函数。 (本例中为 foo) 我尝试在声明为匿名的解析函数中调用此函数。 我已经尝试过使用this 但这不起作用。 我的代码是这样的 var foo = functio
这个问题的灵感来自这个 excellent example .我有 ASP.NET Core MVC 应用程序,我正在编写 unit tests为 Controller 。其中一种方法返回带有匿名类型
我是一名优秀的程序员,十分优秀!