Внедрение переменной в Mono.CSharp.Evaluator (среда выполнения, компилирующая запрос LINQ из строки) - PullRequest
4 голосов
/ 24 сентября 2010

Я использую библиотеку Mono.CSharp для передачи кода. После еще одного вопроса о SO (/2427672/mono-kompilyator-kak-usluga-mcs) мне удалось получить правильную оценку Mono.CSharp на Microsoft CLR.

Чтобы добавить гибкости в мое приложение, я бы хотел иметь возможность настраивать запрос во время выполнения, позволяя пользователю предоставлять запрос LINQ в виде строки, которая обрабатывается и попадает в базу данных при выполнении.

Учитывая этот базовый фрагмент кода:

IQueryable<Contact> contacts = GetContacts();
string query = "from contact in contacts
                where contact.Name == \"name\"
                select contact";
var queryableResult = Mono.CSharp.Evaluator.Evaluate(query);

Как я могу «вставить» переменную контактов в Mono.CSharp.Evaluator, который будет оцениваться как часть запроса? Я иду об этом правильным путем? В конце мне нужно либо полученное выражение, либо IQueryable из строки запроса.

Ответы [ 2 ]

4 голосов
/ 24 сентября 2010

Я думаю, у вас есть несколько вариантов:

  1. Используйте статические или ThreadStatic переменные для обмена данными между вызывающим абонентом и вашим строковым кодом:

    namespace MyNs
    {
      public class MyClass
      {
     [ThreadStatic] // thread static so the data is specific to the calling thread
     public static string MyEnumerableVariable;
    
    
     public void DoSomething() 
     {
          Evaluator.ReferenceAssembly(Assembly.GetExecutingAssembly());
          Evaluator.Run("using MyNs;")
          // run the dynamic code
          var s = @"return (from contact in MyNs.MyClass.MyEnumerableVariable where contact.Name == ""John"" select contact).ToList();";
          Evaluator.Evaluate(s);
     }
    

    } }

  2. Вернуть делегата из вашего строкового кода:

    <code>
     public void DoSomething() 
     {</p>
    
    <p>// run the dynamic code
      var s = @"return new Func<string, IQueryable<MyNs.Model.Contact>, IList>((s,q) => (from contact in q where contact.Name == s select contact).ToList());";
      var func = (Func<string, IQueryable<MyNs.Model.Contact>, IList>)Evaluator.Evaluate(s);
      var result = func("John", myQueryableOfContactsFromNHibernate);</p>
    
    <p>}
    
  3. Пройдите полный маршрут.
<code>
string query = string.Format(
@"using (var dc = new DataContext()) 
{
  return (from contact in dc.Contacts where contact.Name == ""{0}"" select contact).ToList();
}", "John");

var result = Mono.CSharp.Evaluator.Evaluate(query);

2 голосов
/ 24 сентября 2010

Я не пробовал этого, но, думаю, вы могли бы использовать Mono-компилятор для создания делегата, который принимает IQueryable<Contract> в качестве аргумента и возвращает отфильтрованный запрос.Что-то вроде:

IQueryable<Contact> contacts = GetContacts(); 
string query = "new Func<IQueryable<Contact>, IQueryable<Contact>>(contracts =>
                  from contact in contacts 
                  where contact.Name == \"name\" 
                  select contact)"; 
var res = Mono.CSharp.Evaluator.Evaluate(query); 

Тогда вам просто нужно привести res к соответствующему типу Func<,> и вызвать его, чтобы получить результат.

...