Click here to Skip to main content
Click here to Skip to main content

Compiling .NET code on-the-fly

By , 19 Nov 2003
 

Introduction

Sometimes it is useful to add some programmability to your projects, so that a user can change or add logic. This can be done with VBScript and the like, but what fun is that when .NET allows us to play with the compiler? Obviously, your compiled "script" is going to be much faster than interpreted VBScript or Jscript.

I'll show you how to compile VB.NET into an assembly programmatically, in memory, then use that code right away.

Using the code

The demo project is a simple windows application. Here in the article I'll describe how to call a static function; the included project also has example of creating an instance of an object and accessing that instance's properties and methods.

Set up your project and form

The namespaces we'll need for compiling are in System.dll, so they'll be available in a default project in Visual Studio.

Now drag some controls onto the form - you'll need a textbox for the code, a compile button, and a listbox to show your compile errors. They're called txtCode, btnCompile, and lbErrors, respectively. I know, you never get compile errors, but your users might. :-)

Add some code to be compiled

For this demo I'll just put a sample class in the form when it loads. Here is the part of the class definition that I'll use in this article; the demo project has more functionality.

Public Class Sample
    Public Shared Function StaticFunction(ByVal Arg As String) As String
        Return Arg.ToUpper()
    End Function
    
    ...
    
End Class

Implement the compiler

Now we get to the fun part, and it's surprisingly easy. In the compile button's click handler, the following bit of code will compile an assembly from the sample code.

Dim provider As Microsoft.VisualBasic.VBCodeProvider
Dim compiler As System.CodeDom.Compiler.ICodeCompiler
Dim params As System.CodeDom.Compiler.CompilerParameters
Dim results As System.CodeDom.Compiler.CompilerResults

params = New System.CodeDom.Compiler.CompilerParameters
params.GenerateInMemory = True      'Assembly is created in memory
params.TreatWarningsAsErrors = False
params.WarningLevel = 4
'Put any references you need here - even you own dll's, if you want to use one
Dim refs() As String = {"System.dll", "Microsoft.VisualBasic.dll"}
params.ReferencedAssemblies.AddRange(refs)

Try
    provider = New Microsoft.VisualBasic.VBCodeProvider
    compiler = provider.CreateCompiler
    results = compiler.CompileAssemblyFromSource(params, txtCode.Text)
Catch ex As Exception
    'Compile errors don't throw exceptions; you've got some deeper problem...
    MessageBox.Show(ex.Message)
    Exit Sub
End Try

That's it, we're ready to compile! First, though, I want to see any compile errors that my - ahem - user's incorrect code has generated. The CompilerResults object gives me plenty of information, including a list of CompilerError objects, complete with the line and character position of the error. This bit of code adds the errors to my listbox:

lbErrors.Items.Clear()

Dim err As System.CodeDom.Compiler.CompilerError
For Each err In results.Errors
    lbErrors.Items.Add(String.Format( _
        "Line {0}, Col {1}: Error {2} - {3}", _
        err.Line, err.Column, err.ErrorNumber, err.ErrorText))
Next

Use the compiled assembly

Now I want to do something with my compiled assembly. This is where things start to get a little tricky, and the MSDN sample code doesn't help as much. Here I'll describe how to call the the static (shared) function StaticFunction. Sorry about the semantic confusion, I transitioned from MFC...

A member variable in the form class will hold the compiled assembly:

Private mAssembly As System.Reflection.Assembly

The assembly is retrieved from the CompilerResults object, at the end of the btnCompile_Click function:

...        

If results.Errors.Count = 0 Then        'No compile errors or warnings...
    mAssembly = results.CompiledAssembly
End If

I put a couple of text boxes on my form for the function argument and result. To call the static is called by the following code in the test button's click handler:

Dim scriptType As Type
Dim instance As Object
Dim rslt As Object

Try
    'Get the type from the assembly.  This will allow us access to
    'all the properties and methods.
    scriptType = mAssembly.GetType("Sample")

    'Set up an array of objects to pass as arguments.
    Dim args() As Object = {txtArgument.Text}

    'And call the static function
    rslt = scriptType.InvokeMember("StaticFunction", _
        System.Reflection.BindingFlags.InvokeMethod Or _
        System.Reflection.BindingFlags.Public Or _
        System.Reflection.BindingFlags.Static, _
        Nothing, Nothing, args)

    'Return value is an object, cast it back to a string and display
    If Not rslt Is Nothing Then
        txtResult.Text = CType(rslt, String)
    End If
Catch ex As Exception
    MessageBox.Show(ex.Message)
End Try

The key thing here is the InvokeMember call. You can find the definition in MSDN, so I won't go into too much detail. The arguments are as follows:

  1. The first argument is the name of the function, property, or member variable we want to access.
  2. The second argument is a combination of bit flags that defines what we want to do (BindingFlags.InvokeMethod,) and what type of thing we're looking for - BindingFlags.Public Or'd with BindingFlags.Static, which is a function declared as Public Shared in VB.NET. Be careful to get these flags right; if they don't accurately describe the desired function, InvokeMember will throw a MissingMethod exception.
  3. Next is a Binder object; this can be used to perform type conversion for arguments, among other things, but you can get by without it.
  4. Fourth is the target object - that is, the instance of our class. For this static function we don't need the object, so we pass a Nothing.
  5. Finally, we pass the arguments for our function as an array of objects. We can pass by value if we want; just cast the array element back to the right type after calling the function.

The demo code adds buttons for creating an instance of the Sample class and accessing a property and method of that instance. Have fun with it!

Points of Interest

In this example I keep the assembly in a member variable, but that's not strictly necessary. If you use it to create an instance of the class you want to use, and hang onto the Type object and your instance, you can let the assembly go out of scope.

The framework also includes CSharpCodeProvider and JScriptCodeProvider classes, which can be used to compile code written in those languages. The latter is in Microsoft.JScript.dll.

I think I remember reading somewhere that only the JScript compiler was implemented in the 1.0 version of the framework, and the MSDN documentation of these classes says "Syntax based on .NET Framework version 1.1." However, I had no trouble dropping this code into a VS 2002 project and running it. If anyone has a problem doing that or can clarify what the differences are between the two framework versions, it would be nice to note these in a revision to this article.

History

  • 2003.11.19 - Submitted to CodeProject

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Jim Rogers
Web Developer
United States United States
Member
Jim is a developer working in Auburn, Alabama, USA. He started working as a programmer in 1997; much of his early experience was with MFC and ASP, with brief forays into Java servlets, Borland's OWL, and plain-old windows API.
 
Since 2001 Jim has worked primarily with .NET, writing windows and web applications, windows services, and client-server apps. With a little bit of AS3/Flex code thrown in there.
 
Jim comments code in the first person (much to the amusement of his coworkers,) and feels especially weird writing about himself in the third.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionGREAT JOBmemberAngel578930 Jan '13 - 4:54 
QuestionIn memory compilation?memberNikos Hatzistelios9 Feb '12 - 6:34 
QuestionIs it possible to access from a dynamically created assembly to friend class?memberGreg10214 Jan '11 - 22:46 
QuestionHow to access methods in external module or class? [modified]memberMember 44219504 Oct '09 - 5:48 
QuestionHow to Package and compile the programmmemberMember 459740028 Jul '08 - 7:42 
QuestionAccess a windows form control on the Entry assembly from a dynamically created assembly.membergadya18 Jul '08 - 3:42 
AnswerRe: Access a windows form control on the Entry assembly from a dynamically created assembly.memberJim Rogers20 Jul '08 - 8:19 
GeneralRe: Access a windows form control on the Entry assembly from a dynamically created assembly.membergadya21 Jul '08 - 4:21 
GeneralPassing an array to a MethodmemberMisterT9916 Oct '07 - 5:41 
GeneralRe: Passing an array to a MethodmemberJim Rogers19 Oct '07 - 2:31 
GeneralGreat JobmemberSFWheeler20 Feb '07 - 9:24 
QuestionUse a class of current project inside the assembly?memberLee Sing13 Dec '06 - 6:13 
AnswerRe: Use a class of current project inside the assembly?memberLee Sing14 Dec '06 - 2:18 
GeneralRe: Use a class of current project inside the assembly?membercelsoalejo11 Sep '09 - 2:18 
Generalcompiling .net code on the fly[c# programs]memberkaraneshwar14 May '06 - 10:33 
GeneralRe: compiling .net code on the fly[c# programs]memberJim Rogers15 May '06 - 5:30 
Generalhimembernbcbm22 Jan '06 - 23:01 
GeneralRe: himemberJim Rogers23 Jan '06 - 4:32 
GeneralRe: himembernbcbm24 Jan '06 - 6:43 
GeneralRe: himemberJim Rogers24 Jan '06 - 8:57 
GeneralRe: himembernbcbm24 Jan '06 - 22:24 
GeneralPocket PC Compilationmemberrimblock3 Jan '06 - 2:42 
GeneralVB.NetmemberVijarM8 Aug '05 - 1:35 
GeneralSandboxingmemberDrGUI29 Apr '05 - 10:57 
GeneralRe: SandboxingmemberJim Rogers30 Apr '05 - 10:34 
GeneralNeed help on VB compilersussAnonymous27 Apr '05 - 10:20 
GeneralRe: Need help on VB compilermemberJim Rogers30 Apr '05 - 10:24 
GeneralRe: Need help on VB compilermembercathywang20 May '05 - 10:05 
GeneralRe: Need help on VB compilermembercathywang20 May '05 - 10:10 
GeneralVery nicely donememberterpy21 Apr '05 - 7:16 
Generalunit testing tool in vbmemberumakanna8 Mar '05 - 20:10 
GeneralRe: unit testing tool in vbmemberJim Rogers30 Apr '05 - 10:28 
QuestionHow can I reference an object in my executing assembly?memberJim Ptak9 Dec '04 - 12:02 
AnswerRe: How can I reference an object in my executing assembly?memberHC7217 Jan '06 - 10:13 
GeneralRe: How can I reference an object in my executing assembly?memberAlexander M. Batishchev2 Feb '07 - 7:02 
GeneralCreating reports in excelsheet from VB.NETmemberamit2530 May '04 - 23:01 
GeneralnicememberKyle Edwards12 May '04 - 4:04 
GeneralExceptionsussSaradhi10 Apr '04 - 0:27 
GeneralRe: ExceptionmemberJochen Kalmbach3 May '04 - 2:05 
GeneralRe: ExceptionmemberSaradhi3 May '04 - 2:14 
GeneralRe: ExceptionmemberJochen Kalmbach3 May '04 - 2:49 
GeneralExceptionmemberSaradhi10 Apr '04 - 0:20 
GeneralSystem.MissingMethodExceptionmemberjeremypettit24 Feb '04 - 10:48 
GeneralRe: System.MissingMethodExceptionmemberjeremypettit24 Feb '04 - 11:21 
GeneralCompile code with resourcesmemberharrison-ne22 Feb '04 - 14:56 
GeneralRe: Compile code with resourcesmemberJim Rogers23 Feb '04 - 11:11 
GeneralRe: Compile code with resourcesmemberJim Rogers23 Feb '04 - 11:15 
GeneralRe: Compile code with resourcesmemberharrison-ne23 Feb '04 - 17:06 
GeneralRe: Compile code with resourcesmemberslava_pvf4 Jun '09 - 23:51 
GeneralOh yes, man !memberabohmann22 Dec '03 - 1:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 20 Nov 2003
Article Copyright 2003 by Jim Rogers
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid