汎用フィルター オブジェクトを表すクラスがあります
public class Filter
{
public string column { get; set; }
public string operator { get; set; }
public string data { get; set; }
}
LambdaExpression
このようなコードのおかげで変換できること
public LambdaExpression ToExpression( IQueryable query ) {
LambdaExpression toReturn = null;
ParameterExpression parameter = Expression.Parameter( query.ElementType, "p" );
MemberExpression memberAccess = GetMemberExpression( column, parameter );
ConstantExpression filter = Expression.Constant( Convert.ChangeType( data, memberAccess.Type ) );
WhereOperation condition = (WhereOperation)StringEnum.Parse( typeof( WhereOperation ), operator );
LambdaExpression lambda = BuildLambdaExpression( memberAccess, filter, parameter, condition, data );
if ( toReturn == null ) {
toReturn = lambda;
}
return toReturn;
}
要件に従って、次のように表現される、フィールドを照会するための一種のナビゲーション シンタックスをFilter
メンバーに含めることができます。column
FieldA.FieldB.Description
- FieldA プロパティから返された型 T の値を取得します
- T の FieldB から返された T1 型の値を取得します
- T2 の説明から返されたタイプ T2 の値を取得します
結果は次のようなラムダです。この結果を任意の拡張メソッドのp.FieldA.FieldB.Description == "data"
パラメーターとして使用できます。Where
IQueryable
問題は、ナビゲーション クエリのメンバーの 1 つがNullable
型の場合に発生します。その場合、FieldA が nullable であると仮定すると、正しいラムダは次のようになります。
p.FieldA != null && p.FieldA.FieldB.Description == "data"
MemberExpression
このようなコードを使用してオブジェクトを構築するときに、このチェックを実装しようとしました
MemberExpression memberAccess = null;
foreach ( var property in column.Split( '.' ) ) {
memberAccess = MemberExpression.Property( memberAccess ?? ( p as Expression ), property );
Type memberType = memberAccess.Type;
if ( memberType.IsGenericType &&
memberType.GetGenericTypeDefinition() == typeof( Nullable<> ) ) {
//Create here an expression of type : memberAccess != null
}
}
これはプリミティブ型には適していますが、たとえば、EFEntityReference
オブジェクト インスタンスなどの他のオブジェクト参照では機能しません。if
前のような条件に別の条件を追加するだけでよいことはわかっています
if ( ( memberType.IsGenericType &&
memberType.GetGenericTypeDefinition() == typeof( Nullable<> ) ) ||
memberType.IsClass ) {
}
しかし、それはあまりにも多くの条件でラムダを生成するジェネリックが多すぎて、それらのほとんどが役に立たないように思えます。
null許容参照をより適切に個別化する方法はありますか?