C# 尝试开发一种新的扩展方法
我正在使用实体框架,并开发了此扩展方法:C# 尝试开发一种新的扩展方法,c#,linq,entity-framework,linq-to-entities,lambda,C#,Linq,Entity Framework,Linq To Entities,Lambda,我正在使用实体框架,并开发了此扩展方法: public static IQueryable<TResult> Like<TResult>(this IQueryable<TResult> query, Expression<Func<TResult, string>> field, string value) { var expression = Expression.Lambda<Func<TResult, bo
public static IQueryable<TResult> Like<TResult>(this IQueryable<TResult> query, Expression<Func<TResult, string>> field, string value)
{
var expression = Expression.Lambda<Func<TResult, bool>>(
Expression.Call(field.Body, typeof(string).GetMethod("Contains"),
Expression.Constant(value)), field.Parameters);
return query.Where(expression);
}
现在我需要以编程方式调用此扩展方法:
public static IQueryable<TSource> SearchInText<TSource>(this IQueryable<TSource> source, string textToFind)
{
// Collect fields
PropertyInfo[] propertiesInfo = source.ElementType.GetProperties();
List<string> fields = new List<string>();
foreach (PropertyInfo propertyInfo in propertiesInfo)
{
if (
(propertyInfo.PropertyType == typeof(string)) ||
(propertyInfo.PropertyType == typeof(int)) ||
(propertyInfo.PropertyType == typeof(long)) ||
(propertyInfo.PropertyType == typeof(byte)) ||
(propertyInfo.PropertyType == typeof(short))
)
{
fields.Add(propertyInfo.Name);
}
}
ParameterExpression parameter = Expression.Parameter(typeof(TSource), source.ElementType.Name);
Expression expression = Expression.Lambda(Expression.Property(parameter, typeof(TSource).GetProperty(fields[0])), parameter);
Expression<Func<TSource, string>> field = Expression.Lambda<Func<TSource, string>>(expression, parameter);
return source.Like(field, textToFind);
}
public static IQueryable SearchInText(此IQueryable源,字符串textToFind)
{
//集田
PropertyInfo[]propertiesInfo=source.ElementType.GetProperties();
列表字段=新列表();
foreach(PropertyInfo PropertyInfo中的PropertyInfo)
{
如果(
(propertyInfo.PropertyType==typeof(字符串))||
(propertyInfo.PropertyType==typeof(int))||
(propertyInfo.PropertyType==类型(长))||
(propertyInfo.PropertyType==typeof(字节))||
(propertyInfo.PropertyType==typeof(短))
)
{
fields.Add(propertyInfo.Name);
}
}
ParameterExpression参数=Expression.parameter(typeof(TSource),source.ElementType.Name);
Expression=Expression.Lambda(Expression.Property(参数,typeof(TSource).GetProperty(字段[0])),参数);
表达式字段=表达式.Lambda(表达式,参数);
返回source.Like(字段,textToFind);
}
现在这个代码不起作用了!
我需要了解如何声明类似扩展方法的“字段”
Expression<Func<TSource, string>> field = Expression.Lambda<Func<TSource, string>>(expression, parameter);
Expression field=Expression.Lambda(表达式,参数);
在运行时,我收到以下错误:不可能的实用程序un'espressine di tipo'System.Func`2[TestMdf.Equipment,System.String]'per un tipo restituto'System.String'我假设您的第二个代码片段只是一个截断的示例-如果您真的这样做了,那么结果将是不可预测的,因为您使用的是反射返回的第一个属性,它可以在程序运行之间更改 如果你说“这起作用了”,然后描述发生了什么,“这没起作用”,然后描述如何判断它不起作用(编译器错误?运行时错误?异常消息?),你会得到更好的答案 首先,你知道吗?它允许您在运行时才决定如何构造查询,并可能为您解决许多问题 但假设这是一个学习练习 您的
Like
扩展方法采用一个表达式(调用者通常应该将其写成lambda,因为这就是这些内容的全部要点)。该表达式将转换查询结果集中的“记录”,并返回字符串值(可能是从记录中存储的数据中选择)。该方法还接受一个值字符串
但它随后(手动)构造自己的谓词,调用字段
lambda主体上的Contains
方法
我想这应该行得通,因为lambda的结果是一个字符串。然而,我不明白你为什么要这么做。有什么问题吗
var result = from e in context.es
where e.Field.Contains("xxx"))
select e
现在我找到了问题的部分解决方案:
public static IQueryable<TSource> SearchInText<TSource>(this IQueryable<TSource> source, string textToFind)
{
// Collect fields
PropertyInfo[] propertiesInfo = source.ElementType.GetProperties();
List<string> fields = new List<string>();
foreach (PropertyInfo propertyInfo in propertiesInfo)
{
if (
(propertyInfo.PropertyType == typeof(string)) ||
(propertyInfo.PropertyType == typeof(int)) ||
(propertyInfo.PropertyType == typeof(long)) ||
(propertyInfo.PropertyType == typeof(byte)) ||
(propertyInfo.PropertyType == typeof(short))
)
{
fields.Add(propertyInfo.Name);
}
}
ParameterExpression parameter = Expression.Parameter(typeof(TSource), source.ElementType.Name);
var property = typeof(TSource).GetProperty(fields[0]);
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var constantValue = Expression.Constant(textToFind);
var equality = Expression.Call(Expression.Call(Expression.Property(parameter, property), "ToUpper", null, null), typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(textToFind.ToUpper()));
return source.Where(Expression.Lambda<Func<TSource, bool>>(equality, parameter));
}
一些想法?这是我的第一个版本:
public static IQueryable<TSource> SearchInText<TSource>(this IQueryable<TSource> source, string textToFind)
{
if (textToFind.Trim() == "")
{
return source;
}
string[] textToFindList = textToFind.Replace("'", "''").Split(' ');
// Collect fields
PropertyInfo[] propertiesInfo = source.ElementType.GetProperties();
List<string> fieldList = new List<string>();
foreach (PropertyInfo propertyInfo in propertiesInfo)
{
if (
(propertyInfo.PropertyType == typeof(string)) ||
(propertyInfo.PropertyType == typeof(int)) ||
(propertyInfo.PropertyType == typeof(long)) ||
(propertyInfo.PropertyType == typeof(byte)) ||
(propertyInfo.PropertyType == typeof(short))
)
{
fieldList.Add(propertyInfo.Name);
}
}
ParameterExpression parameter = Expression.Parameter(typeof(TSource), source.ElementType.Name);
MethodInfo concatMethod = typeof(String).GetMethod("Concat", new Type[] { typeof(string), typeof(string) });
var spaceExpression = Expression.Constant(" ");
var concatenatedField = BinaryExpression.Add(spaceExpression, Expression.MakeMemberAccess(parameter, typeof(TSource).GetProperty(fieldList[0])), concatMethod);
for (int i = 1; i < fieldList.Count; i++)
{
concatenatedField = BinaryExpression.Add(concatenatedField, spaceExpression, concatMethod);
concatenatedField = BinaryExpression.Add(concatenatedField, Expression.MakeMemberAccess(parameter, typeof(TSource).GetProperty(fieldList[i])), concatMethod);
}
concatenatedField = BinaryExpression.Add(concatenatedField, spaceExpression, concatMethod);
var fieldsExpression = Expression.Call(concatenatedField, "ToUpper", null, null);
var clauseExpression = Expression.Call(
fieldsExpression, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),
Expression.Constant(textToFindList[0].ToUpper())
);
if (textToFindList.Length == 1)
{
return source.Where(Expression.Lambda<Func<TSource, bool>>(clauseExpression, parameter));
}
BinaryExpression expression = Expression.And(Expression.Call(
fieldsExpression, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),
Expression.Constant(textToFindList[1].ToUpper())
), clauseExpression);
for (int i = 2; i < textToFindList.Length; i++)
{
expression = Expression.And(Expression.Call(
fieldsExpression, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),
Expression.Constant(textToFindList[i].ToUpper())
), expression);
}
return source.Where(Expression.Lambda<Func<TSource, bool>>(expression, parameter));
}
public static IQueryable SearchInText(此IQueryable源,字符串textToFind)
{
如果(textToFind.Trim()=“”)
{
返回源;
}
字符串[]textToFindList=textToFind.Replace(“”,““””).Split(“”);
//集田
PropertyInfo[]propertiesInfo=source.ElementType.GetProperties();
列表字段列表=新列表();
foreach(PropertyInfo PropertyInfo中的PropertyInfo)
{
如果(
(propertyInfo.PropertyType==typeof(字符串))||
(propertyInfo.PropertyType==typeof(int))||
(propertyInfo.PropertyType==类型(长))||
(propertyInfo.PropertyType==typeof(字节))||
(propertyInfo.PropertyType==typeof(短))
)
{
fieldList.Add(propertyInfo.Name);
}
}
ParameterExpression参数=Expression.parameter(typeof(TSource),source.ElementType.Name);
MethodInfo concatMethod=typeof(String).GetMethod(“Concat”,新类型[]{typeof(String),typeof(String)});
var spaceExpression=Expression.Constant(“”);
var concatenatedField=BinaryExpression.Add(spaceExpression,Expression.MakeMemberAccess(参数,typeof(TSource).GetProperty(fieldList[0])),concatMethod);
for(int i=1;i
我将修改以管理一些规则,如“短语”+和-operator。我对您的第二个扩展方法有点困惑。循环遍历元素上的所有PropertyInfo,将它们添加到字段集合中,然后只选择第一个字段
" " + fields[0] + " " + ... fields[n]
public static IQueryable<TSource> SearchInText<TSource>(this IQueryable<TSource> source, string textToFind)
{
if (textToFind.Trim() == "")
{
return source;
}
string[] textToFindList = textToFind.Replace("'", "''").Split(' ');
// Collect fields
PropertyInfo[] propertiesInfo = source.ElementType.GetProperties();
List<string> fieldList = new List<string>();
foreach (PropertyInfo propertyInfo in propertiesInfo)
{
if (
(propertyInfo.PropertyType == typeof(string)) ||
(propertyInfo.PropertyType == typeof(int)) ||
(propertyInfo.PropertyType == typeof(long)) ||
(propertyInfo.PropertyType == typeof(byte)) ||
(propertyInfo.PropertyType == typeof(short))
)
{
fieldList.Add(propertyInfo.Name);
}
}
ParameterExpression parameter = Expression.Parameter(typeof(TSource), source.ElementType.Name);
MethodInfo concatMethod = typeof(String).GetMethod("Concat", new Type[] { typeof(string), typeof(string) });
var spaceExpression = Expression.Constant(" ");
var concatenatedField = BinaryExpression.Add(spaceExpression, Expression.MakeMemberAccess(parameter, typeof(TSource).GetProperty(fieldList[0])), concatMethod);
for (int i = 1; i < fieldList.Count; i++)
{
concatenatedField = BinaryExpression.Add(concatenatedField, spaceExpression, concatMethod);
concatenatedField = BinaryExpression.Add(concatenatedField, Expression.MakeMemberAccess(parameter, typeof(TSource).GetProperty(fieldList[i])), concatMethod);
}
concatenatedField = BinaryExpression.Add(concatenatedField, spaceExpression, concatMethod);
var fieldsExpression = Expression.Call(concatenatedField, "ToUpper", null, null);
var clauseExpression = Expression.Call(
fieldsExpression, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),
Expression.Constant(textToFindList[0].ToUpper())
);
if (textToFindList.Length == 1)
{
return source.Where(Expression.Lambda<Func<TSource, bool>>(clauseExpression, parameter));
}
BinaryExpression expression = Expression.And(Expression.Call(
fieldsExpression, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),
Expression.Constant(textToFindList[1].ToUpper())
), clauseExpression);
for (int i = 2; i < textToFindList.Length; i++)
{
expression = Expression.And(Expression.Call(
fieldsExpression, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),
Expression.Constant(textToFindList[i].ToUpper())
), expression);
}
return source.Where(Expression.Lambda<Func<TSource, bool>>(expression, parameter));
}