2013-03-29 41 views
0

我遇到了構建可用於多種不同類型對象的通用搜索表達式的問題。我遇到的問題是一些屬性將包含一個空值。構建通用搜索表達式 - InvalidOperationException:與不能爲空的類型一起使用的合併

這個函數的作用是調用每個屬性的ToString方法,看它是否包含該特定屬性的搜索值。問題是,如果它是空的。如果我嘗試合併,則拋出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

我需要了使用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; 
    } 
相關問題