我遇到了构建通用搜索表达式的问题,该表达式可以处理多种不同类型的对象。我遇到的问题是某些属性将包含空值。
此函数将执行的操作是在每个属性上调用ToString方法,并查看它是否包含该特定属性的搜索值。问题是,如果它是空的。如果我尝试Coalesce它会抛出InvalidOperationException: Coalesce used with type that cannot be null
异常。
这是一个简单的类:
public class SomeObject
{
public int IntValue { get; set; }
public string StringValue { get; set; }
}
示例程序:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
class Program
{
static void Main(string[] args)
{
//Generate data
var list = (new List<SomeObject>
{
new SomeObject { IntValue = 5, StringValue = "abc" },
new SomeObject { IntValue = 10, StringValue = "abc" },
new SomeObject { IntValue = 10 },
new SomeObject { StringValue = "xyz" },
new SomeObject()
}).AsQueryable<SomeObject>();
var searchValues = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("IntValue", "5"),
new KeyValuePair<string, string>("StringValue", "abc")
};
var whereExp = GenerateSearchExpression<SomeObject>(searchValues);
var asdf = list.Where(whereExp).ToList();
System.Diagnostics.Debugger.Break();
}
static Expression<Func<SomeObject, bool>> GenerateSearchExpression<dataType>(List<KeyValuePair<string, string>> values)
{
//Get the properties of the data type
var objectType = typeof(dataType);
var objProps = objectType.GetProperties();
Expression whereExpr = Expression.Constant(true);
var paramExpr = Expression.Parameter(typeof(SomeObject), "val");
//Cycle through each property
foreach (var searchValue in values)
{
var propExpr = Expression.Property(paramExpr, searchValue.Key);
var emptyString = Expression.Constant("");
//InvalidOperationException: Coalesce used with type that cannot be null
var coalesceExpr = Expression.Coalesce(propExpr, emptyString);
var toStringExpr = Expression.Call(coalesceExpr, "ToString", new Type[0]);
var toLowerExpr = Expression.Call(toStringExpr, "ToLower", new Type[0]);
var containExpr = Expression.Call(toLowerExpr, typeof(string).GetMethod("Contains"), Expression.Constant(searchValue.Value));
//Add this to the exisiting where expression.
whereExpr = Expression.And(whereExpr, containExpr);
}
var foobar = Expression.Lambda<Func<SomeObject, bool>>(whereExpr, paramExpr);
return foobar;
}
}
任何想法如何做到这一点?
答案 0 :(得分:0)
我需要使用propExpr.Type.IsValueType
属性:
以下是最终功能:
static Expression<Func<SomeObject, bool>> GenerateSearchExpression<dataType>(List<KeyValuePair<string, string>> values)
{
//Get the properties of the data type
var objectType = typeof(dataType);
var objProps = objectType.GetProperties();
Expression whereExpr = Expression.Constant(true);
var paramExpr = Expression.Parameter(typeof(SomeObject), "val");
MethodCallExpression toStringExpr;
foreach (var searchValue in values)
{
var propExpr = Expression.Property(paramExpr, searchValue.Key);
if (propExpr.Type.IsValueType == true)
{
toStringExpr = Expression.Call(propExpr, "ToString", new Type[0]);
}
else
{
var emptyString = Expression.Constant("");
var coalesceExpr = Expression.Coalesce(propExpr, emptyString);
toStringExpr = Expression.Call(coalesceExpr, "ToString", new Type[0]);
}
var toLowerExpr = Expression.Call(toStringExpr, "ToLower", new Type[0]);
var containExpr = Expression.Call(toLowerExpr, typeof(string).GetMethod("Contains"), Expression.Constant(searchValue.Value));
//Add this to the exisiting where expression.
whereExpr = Expression.And(whereExpr, containExpr);
}
var foobar = Expression.Lambda<Func<SomeObject, bool>>(whereExpr, paramExpr);
return foobar;
}