Знаки сравнения из string

508
30 декабря 2016, 09:42

Всем привет.Интересна такая вещь,можно ли получить знаки сравнения (> < = >= <=) из string и потом использовать их?

public class Main
{
   List<ListItem> ls = new List<ListItem>();
   private void FilterButtonClick(...)
   {
   if(Combobox1.SelectedText == "Id")
   {
       if(Combobox2.Selectedtext == ">=")
       {
       var its = ls.Where(z=>z.Id>=Convert.ToInt32(Textbox1.Text)).ToList();
       for(int i = 0;i<its.Count;i++)
       {
       datagridview.Rows.Add(Its[i].Name);
       }
       else if(Combobox2.Selectedtext == "<=")
       {
       var its = ls.Where(z=>z.Id<=Convert.ToInt32(Textbox1.Text)).ToList();
       for(int i = 0;i<its.Count;i++)
       {
       datagridview.Rows.Add(Its[i].Name);
       }
       }
   }
   else if(Combobox1.SelectedText == "Age")
   {
   if(Combobox2.Selectedtext == ">=")
       {
       var its = ls.Where(z=>z.Age>=Convert.ToInt32(Textbox1.Text)).ToList();
       for(int i = 0;i<its.Count;i++)
       {
       datagridview.Rows.Add(Its[i].Name);
       }
       else if(Combobox2.Selectedtext == "<=")
       {
       var its = ls.Where(z=>z.Age<=Convert.ToInt32(Textbox1.Text)).ToList();
       for(int i = 0;i<its.Count;i++)
       {
       datagridview.Rows.Add(Its[i].Name);
       }
       }
   }
   }
}
public class ListItem
{
string Name;
int Id;
int Age;
int birthday_date;
int Height;
int Weight;
}

Знаю код лучше было делать с Switch.Но писал на сайте и так было удобней.

Answer 1

Например, для int:

Func<int, int, bool> ConstructRelation(string s)
{
    switch (s)
    {
        case ">":  return (Func<int, int, bool>)((a, b) => a > b);
        case "<":  return (Func<int, int, bool>)((a, b) => a < b);
        case "==": return (Func<int, int, bool>)((a, b) => a == b);
        case ">=": return (Func<int, int, bool>)((a, b) => a >= b);
        case "<=": return (Func<int, int, bool>)((a, b) => a <= b);
        default: throw new ArgumentException("Unknown relation");
    }
}

Пользоваться так:

Func<int, int, bool> rel = ConstructRelation(">");
Console.WriteLine(rel(5, 4)); // выводит True

Рабочий код: http://ideone.com/UWgKlU

Пользоваться можно примерно так:

Func<ListItem, int> firstGetter = null;
switch (Combobox1.SelectedText)
{
    case "Id": firstGetter = z => z.Id; break;
    case "Age": firstGetter = z => z.Age; break;
    // тут остальные значения
    default: throw new ArgumentException();
}
int secondValue = Convert.ToInt32(Textbox1.Text);
Func<int, int, bool> rel = ConstructRelation(Combobox2.Selectedtext);
var its = ls.Where(z => rel(firstGetter(z), secondValue));
foreach(var item in its)
{
    datagridview.Rows.Add(item.Name);
}
Answer 2

Через Scripting API:

> Install-Package Microsoft.CodeAnalysis.CSharp.Scripting

[пакет с пачкой зависимостей, может долго скачиваться]

И после этого можно собирать код на лету:

using System;
using Microsoft.CodeAnalysis.CSharp.Scripting;
namespace ConsoleApplication27
{
    public class Globals
    {
        public int X;
        public int Y;
    }
    class Program
    {
        static void Main(string[] args)
        {
            var globals = new Globals { X = 1, Y = 2 };
            string op = ">";
            Console.WriteLine(CSharpScript.EvaluateAsync<bool>($"X{op}Y", globals: globals).Result);
        }
    }
}

При реальном использовании стоит добавить кэширование и принудительную компиляцию через Compile() + RunAsync вместо EvaluateAsync.

Для трех знаков сравнения это как из пушки по воробьям. Если объектов мало - то самый простой вариант - switch по знакам сравнения + reflection для извлечения свойства по имени. Дешево, сердито и читабельно.

Если объектов много - то можно пропробовать собрать лямбду для сравнения на лету:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Linq;
namespace ConsoleApplication27
{
    class ListItem
    {
        public int Id { get; set; }
        public int Age { get; set; }
        public string Name { get; set; }
    }
    class Program
    {
        static readonly Dictionary<string, ExpressionType> opsMap =
            new Dictionary<string, ExpressionType>
            {
                {  ">=", ExpressionType.GreaterThanOrEqual },
                {  "==", ExpressionType.Equal },
                {  "<=", ExpressionType.LessThanOrEqual }
            };
        static void Main(string[] args)
        {
            string operation = ">=";
            string fieldToCompare = "Age";
            string textToCompare = "15";
            List<ListItem> ls = new List<ListItem>
            {
                new ListItem { Age = 10, Name = "a" },
                new ListItem { Age = 20, Name = "b" },
            };
            var listItemType = typeof(ListItem);
            var propToCompare = listItemType.GetProperty(fieldToCompare);
            var valueToCompare = Convert.ChangeType(textToCompare, propToCompare.PropertyType);
            // собираем лямбду x => x.Age >= 15
            var param = Expression.Parameter(listItemType);
            var predicate = Expression.Lambda<Func<ListItem, bool>>(
                Expression.MakeBinary(opsMap[operation],
                    Expression.Property(param, propToCompare),
                    Expression.Constant(valueToCompare)),
                param); // .Compile и кэш при необходимости
            // убрать AsQueryable если выше используется Compile
            var result = ls.AsQueryable().Where(predicate).ToList();
        }
    }
}
READ ALSO
Как узнать, является ли список или массив пустым

Как узнать, является ли список или массив пустым

Каким образом можно узнать, что в списке или массиве не содержится ни одного элемента?

384
Вызвать свойства окна [требует правки]

Вызвать свойства окна [требует правки]

Нужно вызвать свойства из своего приложения (путем нажатия кнопки) окна cmd с использованием c# или winapi по примеру скриншота, вся информации...

351
Как правильно реализовать работу окон?

Как правильно реализовать работу окон?

Первое окно запускается

376
Как распарсить JSON с помощью JSON.Net C#? [требует правки]

Как распарсить JSON с помощью JSON.Net C#? [требует правки]

Нужно распарсить следующий JSON :

373