5

Is there any way to load a .txt file as a class, which my main program can then call functions from? I'm basically trying to add mod support to my simple app, where the user can select options from each file. The file follows a similar (but not the same) format, with a bunch of voids (functions) that are called in the main program.

How can I do this? Is that even possible to do (probably not, answering my own question?), considering it wouldn't be compiled along with the rest of the program?

Thanks!

Scott
  • 5,338
  • 5
  • 45
  • 70
  • It's possible, but you have to invoke the C# compiler.. non-trivial. Easier to require your mods to be compiled into dlls, which you can then load and call into with reflection. – Blorgbeard Jul 31 '12 at 23:40
  • Probably have to look into using Roslyn – Prescott Jul 31 '12 at 23:40

3 Answers3

6

See me answer to this question: Compile a C# Array at runtime and use it in code?

Essentially, you would want to pull your text file into the CodeDom and compile it. After that, it would likely be helpful to create a few dynamic methods as execution helpers.

  • Receive uploaded file
  • Perform any needed validation on the file
  • Read the file as a string into the CodeDom
  • Deal with any compiler/structure errors
  • Create helper methods using Linq expression trees or dynamic methods so that the linkage between the new class and existing code is bridged with a compiled object (otherwise, all the new methods would need to be invoked using reflection)

var csc = new CSharpCodeProvider( new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } } );
var cp = new CompilerParameters() {
    GenerateExecutable = false,
    OutputAssembly = outputAssemblyName,
    GenerateInMemory = true
};

cp.ReferencedAssemblies.Add( "mscorlib.dll" );
cp.ReferencedAssemblies.Add( "System.dll" );

StringBuilder sb = new StringBuilder();

// The string can contain any valid c# code

sb.Append( "namespace Foo{" );
sb.Append( "using System;" );
sb.Append( "public static class MyClass{");
sb.Append( "}}" );

// "results" will usually contain very detailed error messages
var results = csc.CompileAssemblyFromSource( cp, sb.ToString() );

Also, see this topic: Implementing a scripting language in C#. IronPython with the DLR might be suitable for your needs.

Community
  • 1
  • 1
Tim M.
  • 53,671
  • 14
  • 120
  • 163
  • That's the thing - I don't necessarily want to compile it, I just need it to run as a script. – Scott Jul 31 '12 at 23:46
  • 1
    I see. FYI, Scripts are compiled too, just on the fly. Depending on your performance needs, dynamic compilation can be suitable, though c# compilation is probably less optimized for on the fly operations. – Tim M. Jul 31 '12 at 23:48
3

You could load a text file and then use some Compiler-as-a-service (either Microsoft's pre-release Roslyn project or Mono.CSharp). Then you can take the compiled outputs and run them in your program.

If it's at all possible to get your user to hand you a compiled assembly instead of an uncompiled source file, you should consider the Managed Extensibility Framework or Mono.Addins.

The second approach (extension assemblies) seems better to me for at least two reasons: 1) your user can use whatever development environment they'd like to make sure their code compiles correctly before handing it over to you, and 2) you have less work to do to validate input and handle failures.

sblom
  • 26,911
  • 4
  • 71
  • 95
  • Thank you! I'll check out Roslyn, there's a few comments talking about that. – Scott Jul 31 '12 at 23:45
  • 2
    Don't underestimate Mono.CSharp--it's a "finished product" whose interface you can expect to not change. Roslyn's interface will quite probably change between the current CTP state and its final RTM. Once it's closer to shipping, Roslyn might be a more appropriate choice for a typical .NET project, but remember that Mono assemblies run on Microsoft's CLR just as well as any other assemblies do. – sblom Jul 31 '12 at 23:48
1

Use a Framework that Handles Plugins

The Managed Extensibility Framework is just what you're looking for

http://mef.codeplex.com/

The Managed Extensibility Framework (MEF) is a composition layer for .NET that improves the flexibility, maintainability and testability of large applications. MEF can be used for third-party plugin extensibility, or it can bring the benefits of a loosely-coupled plugin-like architecture to regular applications.

The MEF provides a well-defined architecture to support plugins in your application.

DLL vs. Text (Source Code)

The plugin developer is expected to provide a DLL containing the plugin code. However, if needed, you can compile source code into a DLL for them using Roslyn. Keep in mind that if you want to support receiving the plugin source code, you will also have to provide support for helping the user deal with compiler errors and debugging the plugin within your framework. It may be wiser to require them to provide a DLL.

Eric J.
  • 147,927
  • 63
  • 340
  • 553