Injection d'une variable dans Mono.CSharp.Evaluator (exécution compilant une requête LINQ à partir d'une chaîne)

c# expression-trees linq

Question

J'utilise la bibliothèque Mono.CSharp pour émettre du code. Suite à une autre question sur SO (http://stackoverflow.com/questions/3407318/mono-compiler-as-a-service-mcs), j’ai réussi à faire évaluer Mono.CSharp correctement sur le CLR de Microsoft.

Pour ajouter de la flexibilité à mon application, j'aimerais pouvoir personnaliser une requête au moment de l'exécution - en permettant à l'utilisateur de fournir une requête LINQ sous la forme d'une chaîne qui est analysée et frappe la base de données lorsqu'elle est exécutée.

Étant donné cet extrait de code de base:

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

Comment puis-je «injecter» la variable de contacts dans Mono.CSharp.Evaluator pour qu'elle soit évaluée dans le cadre de la requête? Est-ce que j'y vais de la bonne façon? En fin de compte, j'ai besoin de l'expression résultante ou de la requête IQueryable de la chaîne 'query'.

Réponse acceptée

Je pense que vous avez quelques options:

  1. Utilisez des variables statiques ou ThreadStatic pour échanger des données entre le code de l'appelant et votre chaîne:

    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. Renvoyer un délégué de votre code de chaîne:

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

  3. Allez la route complète.
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);
 }


Réponse populaire

Je n’ai pas essayé cela, mais je suppose que vous pourriez utiliser le compilateur Mono pour créer un délégué qui prend IQueryable<Contract> en argument et renvoie la requête filtrée. Quelque chose comme:

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

Ensuite, il vous suffit de convertir res en un type Func<,> approprié et de l'invoquer pour obtenir le résultat.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi