Compiling C# code from APLX
Contents
Although you won't need to do it very often, it's useful to be able to compile C# code directly from APLX. Situations when you might need to do so include:
- When using a third-party library that's provided as C# source code. Although you could compile this using Visual Studio, the following is an alternative if you don't have VS installed.
- On rare occasions in order to use a .NET feature that's not easy to access from APLX.
Disclaimer
What's described here is not a 'conventional' way of accessing C# code. If you have a project that mixes APL and C#, the normal course would be to compile the C# code into a separate library using a tool like Microsoft's Visual Studio. This can then be accessed from APLX by making sure that the library is included in the APLX .NET search path.
See the following Wiki page Calling your own C# code from APLX for more information.
However, you may encounter occasions when dynamic compilation is useful.
Some sample C# code
Here's some sample C# code which we can use to demonstrate dynamic compilation:
using System;
using System.IO;
using System.Windows.Forms;
namespace MyNamespace
{
public class MyClass
{
public int Add (int a, int b)
{
return a+b;
}
}
}If the code is stored in a file on disk, we can read it using ⎕IMPORT, e.g.
code←⎕IMPORT 'C:\simon\example.cs' 'txt'
Alternatively, here's the code in an APL variable if you want to try this example directly:
code←''
code←code,⊂'using System;'
code←code,⊂'using System.IO;'
code←code,⊂'using System.Windows.Forms;'
code←code,⊂'namespace MyNamespace'
code←code,⊂'{'
code←code,⊂' public class MyClass'
code←code,⊂' {'
code←code,⊂' public int Add (int a, int b)'
code←code,⊂' {'
code←code,⊂' return a+b;'
code←code,⊂' }'
code←code,⊂' }'
code←code,⊂'}'
code←∊code
Compiling code dynamically
Here's an example function which uses .NET to compile the code dynamically:
assembly←CompileCode code;CSharpCodeProvider;loParameters;objType;arrayType;codeArray;results;i;err
⍝ Argument 'code' is C# code to compile, as ⎕R-delimited vector
⍝ Result is compiled assembly
⍝ Create compiler
CSharpCodeProvider← '.net' ⎕new 'Microsoft.CSharp.CSharpCodeProvider'
⍝ Create parameters for compiler
loParameters← '.net' ⎕new 'System.CodeDom.Compiler.CompilerParameters'
loParameters.GenerateInMemory←1
⍝ Add reference assemblies. Note that these may vary depending on the C# code being compiled
⊣ loParameters.ReferencedAssemblies.Add 'System.dll'
⊣ loParameters.ReferencedAssemblies.Add 'System.Windows.Forms.dll'
⍝ Convert code to compile into an array containing a single string
objType←'.net' ⎕GETCLASS 'String'
arrayType←'.net' ⎕GETCLASS 'System.Array'
codeArray←arrayType.CreateInstance.⎕REF objType 1
codeArray.SetValue code 0
⍝ Compile it
results←CSharpCodeProvider.CompileAssemblyFromSource loParameters codeArray
⍝ Any errors?
:If results.Errors.Count=0
⍝ All OK
assembly←results.CompiledAssembly
:Else
⍝ Report errors
assembly←⎕NULL
:For i :In (⍳results.Errors.Count)-⎕IO
err←results.Errors.Item i
'Error, Line: ',err.Line.ToString,' - ',err.ErrorText
:EndFor
:EndIf
Testing the code
Here's how to create an instance of the MyClass class defined in the compiled code:
⍝ Compile the code (only need to do this once)
assembly←CompileCode code
⍝ Create an instance of MyClass
obj←assembly.CreateInstance 'MyNamespace.MyClass'
⍝ Did it work?
obj.Add 3 4
7
Author: SimonMarsden
APL Wiki