1

という名前のクラスがありますHomeInfo

public class HomeInfo
{
   public int ID {get;set;}
   public string OwnerName {get;set;}
   public string Address {get;set;}
   public int EstimatedValue {get;set;}
}

サーバーからデータを取得し、それを追加しますList<HomeInfo> listHomeInfo

私のGUIでは、ユーザー入力に基づいて結果をフィルタリングできるようにする必要があるため、クライアントは推定値のテキストボックスが必要で、そこに「> 30kおよび<50k」または「> 50k」などのテキストを入力したいので、これらを解析して変換しましたクラスの値と作成されたオブジェクト

public class ExpressionValue
{
    public float? FirstDigit { get; set; }
    /// <summary>
    /// >, >=, <,<=
    /// </summary>
    public string FirstExpCondition { get; set; }
    /// <summary>
    /// OR, AND
    /// </summary>
    public string ConditionOperator { get; set; }
    public float SecondDigit { get; set; }
    public string SecondExpCondition { get; set; }
}

ExpressionValue オブジェクトを使用すると、適切な条件文字列を作成できます。これで、「EstimatedValue > 30000 AND EstimatedValue < 60000」または「EstimatedValue < 50000」のような条件文字列を作成できるようになりました

私が知る限り、List<T>.Where()文字列条件をサポートしていないため、「List listHomeInfo」にこの条件を効果的に適用する方法がわかりません。それを回避する方法は、リストを DataTable に変換し、Select(string expression)メソッドを使用してから に変換することですが、これを達成するためのより良い方法があると思います。DataRow[]List<HomeInfo>

[編集]

私を助けるために2つのメソッドを作成しましたが、「二項演算子GreaterThanは、タイプ 'System.Single'および 'System.Double'に対して定義されていません。BinaryExpression を作成するとき。

public static Expression<Func<T, bool>> ParseExpressionCondition<T>(string expression, string fieldName)
    {
        try
        {
            string decimalNumRegex = @"\d+(\.\d{1,2})?";
            List<string> matchPatterns = new List<string>() { ">=", ">", "<=", "<" };
            ExpressionValue expValue = new ExpressionValue();
            Dictionary<string, string> conditions = new Dictionary<string, string>();
            var parameter = Expression.Parameter(typeof(T), typeof(T).ToString());
            //var lhs = Expression.GreaterThan(Expression.Property(parameter, "EstimatedValue"), Expression.Constant(30000));
            BinaryExpression lhs = null, rhs = null;
            object objectValue = null;
            string condOperator = null;
            foreach (string pattern in matchPatterns)
            {
                Match match = Regex.Match(expression, pattern + decimalNumRegex);

                if (match.Success)
                {
                    //get digit part
                    double digit = double.Parse(Regex.Match(match.Value, decimalNumRegex).Value);
                    if (!expValue.FirstDigit.HasValue)
                    {
                        objectValue = digit;
                        condOperator = match.Value.Replace(digit.ToString(), "");
                        lhs = GetBinaryExpression(parameter, fieldName, objectValue, condOperator);
                    }
                    else
                    {
                        objectValue = digit;
                        condOperator = match.Value.Replace(digit.ToString(), "");
                        rhs = GetBinaryExpression(parameter, fieldName, objectValue, condOperator);
                    }
                }
            }

            if (expression.ToLower().Contains("and"))
                return Expression.Lambda<Func<T, bool>>(Expression.And(lhs, rhs), parameter);
            else if (expression.ToLower().Contains("or"))
                return Expression.Lambda<Func<T, bool>>(Expression.Or(lhs, rhs), parameter);


            return null;
        }
        catch (Exception ex)
        {
            Logger.WriteLog(ex);
            throw ex;
        }
    }

    private static BinaryExpression GetBinaryExpression(ParameterExpression paraExp, string fieldName, object expressionValue, string conditionOperator)
    {
        try
        {
            BinaryExpression binExp = null;
            MemberExpression expressionLeft = Expression.Property(paraExp, fieldName);
            Expression expressionRight = Expression.Constant(expressionValue );
            switch (conditionOperator)
            {
                case ">":
                    binExp = Expression.GreaterThan(expressionLeft, expressionRight);
                    break;
                case ">=":
                    binExp = Expression.GreaterThanOrEqual(expressionLeft, expressionRight);
                    break;
                case "<":
                    binExp = Expression.LessThan(expressionLeft, expressionRight);
                    break;
                case "<=":
                    binExp = Expression.LessThanOrEqual(expressionLeft, expressionRight);
                    break;
            }
            return binExp;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
4

6 に答える 6

2

解析ロジックがすでにある程度実装されていると仮定すると、(独自のカスタムExpressionValueクラスを使用するのではなく)式ツリーを生成することをお勧めします。

たとえば、'EstimatedValue> 30000 AND EstimatedValue <60000'は、次の形式の式ツリーになる可能性があります。

var parameter = Expression.Parameter(typeof(HomeInfo), "homeInfo");
var lhs = Expression.GreaterThan(Expression.Property(parameter, "EstimatedValue"), Expression.Constant(30000));
var rhs = Expression.LessThan(Expression.Property(parameter, "EstimatedValue"), Expression.Constant(60000));
var expression = Expression.Lambda<Func<HomeInfo, bool>>(Expression.AndAlso(lhs, rhs), parameter);

次に、生成された式ツリーを使用して、次のようにリストを照会できます。

var results = listHomeInfo.AsQueryable().Where(expression);
于 2012-10-01T16:19:52.780 に答える
0

LINQ拡張メソッドを記述します。

public static IEnumerable<HomeInfo> PassesExpression(this IEnumerable<HomeInfo> homes, ExpressionValue expression)
{
    foreach(HomeInfo home in homes)
    {
        bool one, two;

        if(expression.FirstExpCondition == '>')
            one = (home.EstimatedValue > expression.FirstDigit);
        else if(expression.FirstExpCondition == '>=')
            one = (home.EstimatedValue >= expression.FirstDigit);
        else if(expression.FirstExpCondition == '<')
            one = (home.EstimatedValue < expression.FirstDigit);
        else if(expression.FirstExpCondition == '<=')
            one = (home.EstimatedValue <= expression.FirstDigit);

        if(expression.SecondExpCondition == '>')
            two = (home.EstimatedValue > expression.SecondDigit);
        else if(expression.SecondExpCondition == '>=')
            two = (home.EstimatedValue >= expression.SecondDigit);
        else if(expression.SecondExpCondition == '<')
            two = (home.EstimatedValue < expression.SecondDigit);
        else if(expression.SecondExpCondition == '<=')
            two = (home.EstimatedValue <= expression.SecondDigit);

        if((expression.ConditionOperator == 'OR' && (one || two)) || (expression.ConditionOperator == 'AND' && (one && two)))
            yield return home;
    }
}
于 2012-10-01T16:22:59.553 に答える
0

私は通常、値の範囲用に2つのテキストボックスを持っています。1つは最小値用、もう1つは最大値用です。制限が必要ない場合は、空にすることができます

int? min = null
int? max = null;
int i;

if (Int32.TryParse(txtMin.Text, out i) min = i;
if (Int32.TryParse(txtMax.Text, out i) max = i;

string name = txtName.Text;

これらの定義を使用すると、where句を動的に組み合わせることができます

IEnumerable<HomeInfo> result = list;
if (min.HasValue) result = result.Where(h => h.EstimatedValue >= min.Value);
if (max.HasValue) result = result.Where(h => h.EstimatedValue <= max.Value);
if (name != "")
    result = result.Where(
        h => h.OwnerName.StartsWith(name, StringComparison.OrdinalIgnoreCase)
    );
于 2012-10-01T16:23:55.263 に答える
0

車輪を再発明しないでください。NCalcはすでにそのようなことを行っています。

という名前の変数EstimatedValueとユーザー定義の式を使用UserExpressionして、NCalc で次のようにします。

myList.Where(elem => new Expression(EstimatedValue.ToString() + UserExpression).Evaluate());
于 2012-10-01T16:16:06.973 に答える
0

あなたの立場では、ミニルールエンジンを作成します。

そう

public abstract class ExpressionBase {
 public float value {get;set;}
}

public class GreaterThanExpression : ExpressionBase {}
public class LessThanExpression : ExpressionBase {}

入力された文字列を解析すると、入力された式のリストを作成し、それらを必要な順序で IQueryable に適用できます。

于 2012-10-01T16:16:39.487 に答える
-1

use LinqToObjects

List<HomeInfo> homeInfos = new List<HomeInfo>();

homeInfos.Where(x => x.EstimatedValue > 1000).Where(x => x.EstimatedValue < 10000);
于 2012-10-01T16:15:46.443 に答える