I'm using the Mono.CSharp library to emit code. Following another question on SO (http://stackoverflow.com/questions/3407318/mono-compiler-as-a-service-mcs) I managed to get Mono.CSharp evaluating correctly on the Microsoft CLR.
To add flexibility in my app I'd like to be able to customize a query at runtime - by allowing the user to provide a LINQ query as a string that gets parsed and hits the database when executed.
Given this basic snippet of code:
IQueryable<Contact> contacts = GetContacts();
string query = "from contact in contacts
                where contact.Name == \"name\"
                select contact";
var queryableResult = Mono.CSharp.Evaluator.Evaluate(query);
How can I 'inject' the contacts variable into the Mono.CSharp.Evaluator to be evaluated as part of the query? Am I going about this the right way? In the end I either need the resulting Expression or the IQueryable from the 'query' string.
I think you have a few options:
Use static or ThreadStatic variables to exchange data between the caller and you string based code:
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);
 }
} }
Return a delegate from your string code:
 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);
}
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);
                        I didn't try this, but I guess you could use Mono compiler to create a delegate vthat takes IQueryable<Contract> as argument and returns the filtered query. Something like:
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); 
Then you just need to cast res to an appropriate Func<,> type and invoke it to get the result.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With