Ini adalah versi sederhana dari masalah aslinya.
Saya memiliki kelas yang disebut Person:
public class Person {
public string Name { get; set; }
public int Age { get; set; }
public int Weight { get; set; }
public DateTime FavouriteDay { get; set; }
}
... dan katakanlah sebuah instance:
var bob = new Person {
Name = "Bob",
Age = 30,
Weight = 213,
FavouriteDay = '1/1/2000'
}
Saya ingin menulis yang berikut sebagai string di editor teks favorit saya ....
(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3
Saya ingin mengambil string ini dan contoh objek saya dan mengevaluasi BENAR atau SALAH - yaitu mengevaluasi Func <Person, bool> pada instance objek.
Inilah pemikiran saya saat ini:
- Menerapkan tata bahasa dasar di ANTLR untuk mendukung Operator Perbandingan dan Logika dasar. Saya berpikir untuk menyalin prioritas Visual Basic dan beberapa fitur di sini: http://msdn.microsoft.com/en-us/library/fw84t893(VS.80).aspx
- Minta ANTLR membuat AST yang cocok dari string yang disediakan.
- Berjalan AST dan gunakan kerangka kerja Predicate Builder untuk secara dinamis membuat Func <Person, bool>
- Mengevaluasi predikat terhadap instance Person sesuai kebutuhan
Pertanyaan saya adalah apakah saya benar-benar overbaked ini? ada alternatif?
EDIT: Solusi Terpilih
Saya memutuskan untuk menggunakan Dynamic Linq Library, khususnya kelas Dynamic Query yang disediakan di LINQSamples.
Kode di bawah ini:
using System;
using System.Linq.Expressions;
using System.Linq.Dynamic;
namespace ExpressionParser
{
class Program
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public int Weight { get; set; }
public DateTime FavouriteDay { get; set; }
}
static void Main()
{
const string exp = @"(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3";
var p = Expression.Parameter(typeof(Person), "Person");
var e = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p }, null, exp);
var bob = new Person
{
Name = "Bob",
Age = 30,
Weight = 213,
FavouriteDay = new DateTime(2000,1,1)
};
var result = e.Compile().DynamicInvoke(bob);
Console.WriteLine(result);
Console.ReadKey();
}
}
}
Hasilnya adalah tipe System.Boolean, dan dalam hal ini BENAR.
Banyak terima kasih kepada Marc Gravell.
Termasuk System.Linq. Paket nuget dinamis, dokumentasi di sini
Jawaban:
Apakah pustaka linq dinamis membantu di sini? Secara khusus, saya berpikir sebagai
Where
klausa. Jika perlu, letakkan di dalam daftar / larik hanya untuk memanggilnya.Where(string)
! yaituJika tidak, menulis parser (menggunakan di
Expression
bawah tenda) tidak sangat melelahkan - saya menulis yang serupa (walaupun saya tidak berpikir saya memiliki sumber) di kereta saya pergi sebelum xmas ...sumber
// Lambda expression as data in the form of an expression tree.
System.Linq.Expressions.Expression<Func<int, bool>> expr = i => i < 5;
// Compile the expression tree into executable code.
Func<int, bool> deleg = expr.Compile();
// Invoke the method and print the output.
Console.WriteLine("deleg(4) = {0}", deleg(4));
ParseLambda bagus!Perpustakaan lain yang serupa adalah Kabur
Saya melakukan perbandingan cepat Dynamic Linq Library dan Flee and Flee 10 kali lebih cepat untuk ekspresi
"(Name == \"Johan\" AND Salary > 500) OR (Name != \"Johan\" AND Salary > 300)"
Ini cara Anda dapat menulis kode menggunakan Flee.
sumber
LinqPad memiliki
Dump()
metodesumber
var type = typeof(T); var prop = type.GetProperty(propName);
untuk mendapatkannya untuk dikompilasi.Anda mungkin melihat DLR . Ini memungkinkan Anda untuk mengevaluasi dan menjalankan skrip di dalam aplikasi .NET 2.0. Berikut ini contoh dengan IronRuby :
Tentu saja teknik ini didasarkan pada evaluasi runtime dan kode tidak dapat diverifikasi pada waktu kompilasi.
sumber
Berikut ini adalah contoh parser combinator berbasis Scala DSL untuk penguraian dan evaluasi ekspresi aritmatika.
Pohon ekspresi setara atau pohon parse dari ekspresi aritmatika yang disediakan akan menjadi tipe Parser [Daftar [String]].
Lebih detail ada di tautan berikut:
http://nicolaecaralicea.blogspot.ca/2013/04/scala-dsl-for-parsing-and-evaluating-of.html
sumber
Selain Dynamic Linq Library (yang membangun ekspresi yang sangat diketik dan membutuhkan variabel yang sangat diketik) saya menyarankan alternatif yang lebih baik: linq parser bagian dari NReco Commons Library (open source). Ini meluruskan semua jenis dan melakukan semua doa saat runtime dan berperilaku seperti bahasa dinamis:
sumber
Meskipun ini adalah posting yang relatif lama - ini adalah kode untuk pembuat ekspresi: AnyService - ExpressionTreeBuilder Ini adalah unit test: AnyService - ExpressionTreeBuilder Unit Tests
sumber