Hello everyone. Such a thing is interesting, is it possible to get comparison signs (> <=> = <=) from string and then use them?

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; } 

I know the code was better to do with the Switch. But I wrote on the site and it was more convenient.

  • For example, switch ? - VladD
  • In fact it is possible. But it will take 5 times more code. In my case, instead of ~ 100 there will be 500 lines. - Berianidze Luka
  • And what data type do you need to compare? - VladD
  • Int. It is necessary to make a filter in the program. More than 10 variables. So planned in one combobox- variables. In the second there are 3 comparison signs . And the textbox, what values ​​to look for - Berianidze Luka
  • one
    I think it's easier to write your DSL here - Mikhail Vaysman

2 answers 2

For example, for 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"); } } 

Use this:

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

Working code: http://ideone.com/UWgKlU


You can use something like this:

 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); } 
  • I suspect this method will not work, the reason is written in the first message. - Berianidze Luka
  • @ ლუკაბერიანიძე: Suitable, in theory. See the answer update. - VladD
  • Thank you. Helped. - Berianidze Luka
  • @ ლუკა: please! - VladD

Via Scripting API :

 > Install-Package Microsoft.CodeAnalysis.CSharp.Scripting 

[package with a bundle of dependencies, can be downloaded for a long time]

And after that you can collect the code on the fly:

 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); } } } 

In real use, it is worth adding caching and forced compilation via Compile() + RunAsync instead of EvaluateAsync .


For the three signs of comparison, it’s like a cannon on a sparrow. If there are few objects, then the simplest option is to switch by comparison + reflection signs to extract the property by name. Cheap, angry and readable.

If there are a lot of objects, then you can try to collect lambda for comparison on the fly:

 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(); } } } 
  • Wow, simple scripting has appeared in .NET, cool. - VladD