Iniezione di una variabile in Mono.CSharp.Evaluator (runtime che compila una query LINQ da stringa)

c# expression-trees linq

Domanda

Sto usando la libreria Mono.CSharp per emettere il codice. Seguendo un'altra domanda su SO (http://stackoverflow.com/questions/3407318/mono-compiler-as-a-service-mcs) sono riuscito a ottenere Mono.CSharp valutando correttamente su Microsoft CLR.

Per aggiungere flessibilità alla mia app mi piacerebbe essere in grado di personalizzare una query in fase di runtime, consentendo all'utente di fornire una query LINQ come una stringa che viene analizzata e colpisce il database quando viene eseguita.

Dato questo frammento di codice di base:

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

Come posso "iniettare" la variabile contacts in Mono.CSharp.Evaluator per essere valutata come parte della query? Sto andando su questo nel modo giusto? Alla fine ho bisogno dell'espressione risultante o IQueryable dalla stringa 'query'.

Risposta accettata

Penso che tu abbia alcune opzioni:

  1. Utilizza variabili statiche o ThreadStatic per scambiare dati tra il chiamante e il codice basato su stringhe:

    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. Restituisci un delegato dal tuo codice stringa:

    
     public void DoSomething() 
     {

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

    }

  3. Vai al percorso completo.

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


Risposta popolare

Non ho provato questo, ma credo che si possa usare il compilatore Mono per creare un delegato che vada a prendere IQueryable<Contract> come argomento e restituisca la query filtrata. Qualcosa di simile a:

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

Quindi basta lanciare res su un tipo Func<,> appropriato e invocarlo per ottenere il risultato.



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché