Parsing Linq Queries as String with CodeDOM

Goldytech
Posted by in C# category on for Advance level | Views : 7351 red flag

In this post I teach you how can you can dynamically compile any clr compliant code with CodeDom namespace. This article was orginally posted on my blog.
INTRODUCTION

I recently worked on very interesting and challenging project. It was about parsing the dynamic queries that were created by the user as strings. These queries were actual the Linq queries. Initially I thought that it is not possible but then after scratching my head and doing some binging . I came out with a great solution which was satisfying my client needs. Hence I decided to share this achievement of mine with the community as a result of which I am writing this post. I will show you that how you can do a dynamic compilation of any CLR compliant code which is in string format and get the desired output.

CodeDOM

.NET Framework has so much to offer that few of its namespaces gets unnoticed by developer. System.CodeDOM is one of them. CodeDom is the abbreviation and it stands for Code Document Object Model. This namespace has the rich set of the classes which makes the coding a breeze.The namespace includes all the programming aspects classes like Declarations,Parameteres,ClassCreation etc. I won't get into the details of these classes as it is vast topic within itself. Let us jump into the solution and see some code. I have very simple linq query code which is shown below.

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var numbersplusone = (from n in numbers
select n + 1).ToList();
return numbersplusone;
The above code is pretty simple linq which queries the integer array and add one to all its elements and returns the output. As CodeDom doesn’t have the classes yet which can parse the Linq queries. I have to pass the code as a string to the CodeProvider class. I create a StringBuilder object variable and appends my each code line to it. The compiler class object then compiles the code and generates the assembly in memory. Further using the Reflection classes I derived the type of the generated assembly and invoke the function which returns me the value. Enough of talking now let us see some code in action.

static object DynamicCompilation(string Code) {

string functionName = "myFunction";

StringBuilder DynamicCodeToCompile = new StringBuilder();

DynamicCodeToCompile.Append("using System;");

DynamicCodeToCompile.AppendLine();

DynamicCodeToCompile.Append("using System.Collections.Generic;");

DynamicCodeToCompile.AppendLine(); DynamicCodeToCompile.Append("using System.Linq;");

DynamicCodeToCompile.AppendLine(); DynamicCodeToCompile.Append("namespace CodeTest");

DynamicCodeToCompile.AppendLine(); DynamicCodeToCompile.Append("{"); DynamicCodeToCompile.Append("class EvaluateStringLinq");

DynamicCodeToCompile.AppendLine();

DynamicCodeToCompile.Append("{");

DynamicCodeToCompile.AppendFormat("public static object {0}()", functionName);

DynamicCodeToCompile.AppendLine(); DynamicCodeToCompile.Append("{");

DynamicCodeToCompile.Append(Code);

DynamicCodeToCompile.AppendLine();

DynamicCodeToCompile.Append("}"); //function end DynamicCodeToCompile.AppendLine();

DynamicCodeToCompile.Append("}"); //class end

DynamicCodeToCompile.AppendLine();

DynamicCodeToCompile.Append("}"); //namespace end

CodeDomProvider provider;

string language = "cs";

// Check for a provider corresponding to the input language.

if (CodeDomProvider.IsDefinedLanguage(language )) {

provider =new Microsoft.CSharp.CSharpCodeProvider(new Dictionary() { { "CompilerVersion", "v3.5" } });

 //// Get the compiler settings for this language.

CompilerInfo langCompilerInfo = CodeDomProvider.GetCompilerInfo(language);

 CompilerParameters langCompilerConfig = langCompilerInfo.CreateDefaultCompilerParameters();

 langCompilerConfig.ReferencedAssemblies.Add("System.dll");

langCompilerConfig.ReferencedAssemblies.Add("System.Core.dll");

langCompilerConfig.ReferencedAssemblies.Add("System.Data.dll");

langCompilerConfig.ReferencedAssemblies.Add("System.Data.Linq.dll");

langCompilerConfig.GenerateInMemory = true;

langCompilerConfig.TreatWarningsAsErrors = false;

CompilerResults results = provider.CompileAssemblyFromSource(langCompilerConfig, DynamicCodeToCompile.ToString());

if (results.Errors.Count > 0)

{ Console.WriteLine("Errors Occured" + results.Errors.Count); return null; }

else

{

Type dynamicType; dynamicType = results.CompiledAssembly.GetType("CodeTest.EvaluateStringLinq");

MethodInfo method;

method = dynamicType.GetMethod(functionName);

return method.Invoke(null, null);

}

 }

 else

 {

// Tell the user that the language provider was not found.

Console.WriteLine("There is no support for input language \"{0}\".", language); return null; } }

 

CLOSURE

Lot of dynamism is coming now in modern apps. You need to think out of the box to provide the solutions to your clients. I have barely scratch the surface of the CodeDom namespace but this technology has lot to offer. Imagine you can put your entire business rules expressions in some durabale store and evaluate those expressions at runtime with rich object model of this namespace. I think sky is the limit. Download the sample code from here. Rename the extension of the file from .doc to .rar Cheers and Happy Coding ....

Page copy protected against web site content infringement by Copyscape

About the Author

Goldytech
Full Name: Muhammad Afzal Qureshi
Member Level: Bronze
Member Status: Member
Member Since: 8/4/2009 10:58:17 PM
Country: India

http://goldytech.wordpress.com
Hello Everyone Myself Muhammad Afzal , aka GoldyTech. Thats my pen name. I reside in India and work as a solution Architect on .NET platform. I hope you must have enjoyed reading my blog. Please leave your comments or suggestions good or bad and help me to improve

Login to vote for this post.

Comments or Responses

Posted by: Raveendra on: 8/16/2010 | Points: 10
Hey

Thx u saved a ton of my time u are great.

I was on same lines but was missing small thing .......

U Rock

Login to post response

Comment using Facebook(Author doesn't get notification)