0

複数の異なるタイプのオブジェクトで機能する一般的な検索式を作成する際に問題が発生しています。私が直面している問題は、一部のプロパティに null 値が含まれることです。

この関数が行うことは、各プロパティで ToString メソッドを呼び出し、その特定のプロパティの検索値が含まれているかどうかを確認することです。問題は、それが Null の場合です。合体しようとすると、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;
  }
}

これを行う方法はありますか?

4

1 に答える 1

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;
  }
于 2013-03-29T15:52:18.570 に答える