How to dynamically invoke a class based on a string? - c#

Can you give me some guidance to dynamically load class based on name. The name is provided as a argument at runtime.
static void Main(string[] args)
{
...
}
Let's say my argument is "parrot" then I would like to load my parrotProcessor class. If my argument name is "snake" then I load my To make snakeProcessor. Of course this mean I have a parrot and snake processor class that inherit an interface IProcessor. I don't know what could be the list of all processor. this list is maintained by other developers and they can create what they want.
Example of my processor interface:
public interface IProcessor
{
void Process();
}
And in my Program.cs
static void Main(string[] args)
{
var processor = GetProcessor(args[0]);
processor.Process();
}
My question is what should I do in GetProcessor() method?
Here is what I have at this moment:
private IProcessor GetProcessor(string name)
{
switch (name)
{
case "ant":
return new AntProcessor();
case "parrot":
return new ParrotProcessor();
case "snake":
return new SnakeProcessor();
default:
throw new ArgumentException("Case not found");
}
}
But this mean I must updated this ugly switch each time I create a new processor specialized class. This is not possible. I can do it now for development but not for long term.
What are the solutions? Should I use something similar to DI with NInject or am I mixing everything? Can I simply use the Invoke method? And why Invoke or DI? I know this question is kind of open question but it is something that happen often in code of many people so I suppose there is unique best practice about it.

You can use something like the following
var type = Type.GetType("MyFullyQualifiedTypeName");
var myObject = (MyAbstractClass)Activator.CreateInstance(type);
You need to do some string modifications like taking the word, adding the processor string and making sure that all the processors are at the same place.
If you are certain that the type is in the current assembly, simply fully qualified name by this
Activator.CreateInstance(Type.GetType("SomeProcessor"));

First of all, there is absolutely nothing wrong with using a switch block as you are doing. It gets the job done, and it serves as an explicit source of truth with regards to the interpretation of the command-line parameter. It also acts as a whitelist, preventing users from passing a class name that maybe you don't want them to instantiate. Yes, you have to update it every time you add a new class, but you're already adding the class itself, so you are already in a situation where a new version and deployment will be needed.
That being said, there are various reasons why you'd rather have the ability to look up a command line parameter and automatically know which type to instantiate. That is trivial to do with a Dictionary<string,Func<IProcessor>>:
this.Map = new Dictionary<string,Func<IProcessor>>
{
{ "ant", () => new AntProcessor() },
{ "snake", () => new SnakeProcessor() },
{ "parrot", () => new ParrotProcessor() },
{ "lizard", () => new LizardProcessor() }
};
Then you would handle a command-line parameter like this:
//Use the string to look up a delegate
var ok = this.Map.TryGetValue(textFromCommandline, out var func);
//If not found, user entered a bad string
if (!ok) throw new ArgumentException();
//Invoke the delegate to obtain a new instance
IProcessor processor = func();
return processor;
Once you understand the concept of using a map in this way, you can come up with a scheme to populate it automatically, e.g
this.Map = assembly.GetTypes()
.Where( t => typeof(IProcessor).IsAssignableFrom( t ))
.ToDictionary
(
t => t.Name,
t => new Func<IProcessor>( () => Activator.CreateInstance(t) as IProcessor );
);
And you will have met your goal of not having to maintain a hardcoded list anywhere.

You can rewrite private IProcessor GetProcessor(string name) method using a little mix of reflection and LINQ like this:
private IProcessor GetProcessor<Tinterface>(string name) where Tinterface : IProcessor
{
var type = typeof(Tinterface).Assembly.GetTypes()
.First(x => x.FullName.Contains("name"));
return (Tinterface)Activator.CreateInstance(type);
}
Usage:
static void Main(string[] args)
{
var processor = GetProcessor<IProcessor>(args[0]);
processor.Process();
}
This route saves you the stress of typing the fully qualified name of the class

You can try iterate over all exported types in specific assembly:
using System;
using System.Linq;
using System.Reflection;
namespace ConsoleApp
{
public class Program
{
public static void Main (string[] args)
{
Assembly assembly = typeof (Program).Assembly; // use current assembly...
var types = assembly.GetExportedTypes() // public types only
.Where (type => type.GetInterfaces().Contains (typeof (IProcessor))) // interface must be implemented
.Where (type => type.Name.EndsWith ("Processor")) // and maybe use some naming convention?
.ToList();
//string name = args[0];
string name = "Parrot";
Type parrotType = types.Where (x => x.Name.StartsWith (name)).FirstOrDefault();
if (parrotType != null)
{
// it will work only when we implement parameterless constructor for this type
IProcessor parrotInstance = (IProcessor) Activator.CreateInstance (parrotType);
parrotInstance.Process();
}
}
}
public interface IProcessor
{
void Process();
}
public class SnakeProcessor : IProcessor
{
public void Process()
{
}
}
public class ParrotProcessor : IProcessor
{
public void Process()
{
Console.WriteLine ("Parrot Process");
}
}
}

I will add to the answers that suggest using reflection : EX: IProcessor parrotInstance = (IProcessor) Activator.CreateInstance(parrotType); is to make this part of code in a separate Factory class for Processor this way you can reuse the factory class in other places in your code, also even if you decide to keep the switch statement, the changes on the factory class will only affect it without affecting any dependent code.
public interface IProcessorFactory
{
IProcessor GetProcessor(string processorTypeName);
}
Good read:
SOLID Design Principles

Related

Roslyn, how can I instantiate a class in a script during runtime and invoke methods of that class?

I understand how I can execute entire scripts using Roslyn in C# but what I now want to accomplish is to compile a class inside the script, instantiate it, parse it to an interface and then invoke methods that the compiled and instantiated class implements.
Does Roslyn expose such functionality? Can you someone please point me to such approach?
Thanks
I think you can do what you want for example like this:
namespace ConsoleApp2 {
class Program {
static void Main(string[] args) {
// create class and return its type from script
// reference current assembly to use interface defined below
var script = CSharpScript.Create(#"
public class Test : ConsoleApp2.IRunnable {
public void Run() {
System.Console.WriteLine(""test"");
}
}
return typeof(Test);
", ScriptOptions.Default.WithReferences(Assembly.GetExecutingAssembly()));
script.Compile();
// run and you get Type object for your fresh type
var testType = (Type) script.RunAsync().Result.ReturnValue;
// create and cast to interface
var runnable = (IRunnable)Activator.CreateInstance(testType);
// use
runnable.Run();
Console.ReadKey();
}
}
public interface IRunnable {
void Run();
}
}
Instead of returning type you created from script you can also use globals and return it that way:
namespace ConsoleApp2 {
class Program {
static void Main(string[] args) {
var script = CSharpScript.Create(#"
public class Test : ConsoleApp2.IRunnable {
public void Run() {
System.Console.WriteLine(""test"");
}
}
MyTypes.Add(typeof(Test).Name, typeof(Test));
", ScriptOptions.Default.WithReferences(Assembly.GetExecutingAssembly()), globalsType: typeof(ScriptGlobals));
script.Compile();
var globals = new ScriptGlobals();
script.RunAsync(globals).Wait();
var runnable = (IRunnable)Activator.CreateInstance(globals.MyTypes["Test"]);
runnable.Run();
Console.ReadKey();
}
}
public class ScriptGlobals {
public Dictionary<string, Type> MyTypes { get; } = new Dictionary<string, Type>();
}
public interface IRunnable {
void Run();
}
}
Edit to answer your comment.
what if I know the name and type of the class in the script? My
understanding is that script.Compile() adds the compiled assembly to
gac? Am I incorrect? If I then simply use
Activator.CreateInstance(typeofClass) would this not solve my problem
without even having to run the script
Compiled assembly is not added to gac - it is compiled and stored in memory, similar to how you can load assembly with Assembly.Load(someByteArray). Anyway, after you call Compile that assembly is loaded in current app domain so you can access your types without RunAsunc(). Problem is this assembly has cryptic name, for example: ℛ*fde34898-86d2-42e9-a786-e3c1e1befa78#1-0. To find it you can for example do this:
script.Compile();
var asmAfterCompile = AppDomain.CurrentDomain.GetAssemblies().Single(c =>
String.IsNullOrWhiteSpace(c.Location) && c.CodeBase.EndsWith("Microsoft.CodeAnalysis.Scripting.dll"));
But note this is not stable, because if you compile multiple scripts in your app domain (or even same script multiple times) - multiple such assemblies are generated, so it is hard to distinguish between them. If that is not a problem for you - you can use this way (but ensure that you properly test all this).
After you found generated assembly - problems are not over. All your script contents are compiled under wrapping class. I see its named "Submission#0" but I cannot guarantee it's always named like that. So suppose you have class Test in your script. It will be child class of that wrapper, so real type name will be "Submission#0+Test". So to get your type from generated assembly it's better to do this:
var testType = asmAfterCompile.GetTypes().Single(c => c.Name == "Test");
I consider this approach somewhat more fragile compared to previous, but if previous are not applicable for you - try this one.
Another alternative suggested in comments:
script.Compile();
var stream = new MemoryStream();
var emitResult = script.GetCompilation().Emit(stream);
if (emitResult.Success) {
var asm = Assembly.Load(stream.ToArray());
}
That way you create assembly yourself and so do not need to search it in current app domain.

ASP.NET Core dependency injection: Service resolved at runtime using a Func delegate

I'm trying to inject a service to my controllers but I want to inject a different instance of my service depending of several parameters. Actually for this part it's working, I'm able to do it.
What I want is to load a specific instance of IRepository<Database> based on some configuration we get from a configuration file and respecting the DRY rule (don't repeat yourself).
I have these 2 classes:
public abstract class FooServicesProvider
{
public Func<IServiceProvider, IRepository<Database>> DatabaseRepository = provider =>
{
return null;
};
}
public class FooFileSystemServicesProvider : FooServicesProvider
{
public new Func<IServiceProvider, IRepository<Database>> DatabaseRepository = provider =>
{
//Specific code determining which database to use and create a new one if needed
//our databases are FOLDERS containing some files
//knowing how chosenDb.FullName is set is not important here
//[...]
var databaseRepository = new DatabaseFileSystemRepository(chosenDb.FullName);
databaseRepository.testProperty = "Foo value";
return databaseRepository;
};
}
Notice the new keyword used to redefine the code of my Func. This is the best way I found because of the Func delegate, I'm very limited, I can't use it in an Interface neither override it.
Now in my ConfigureServices method in Startup.cs I have this code
var fakeConfiguration = "File";
FooServicesProvider servicesProvider = null;
if(fakeConfiguration == "File")
{
servicesProvider = new FooFileSystemServicesProvider();
}
else
{
servicesProvider = new AnotherFooServicesProvider();
}
//Here is the tricky part
//This should call FooFileSystemServicesProvider.DatabaseRepository because of the "new" keyword, but it's NOT
services.AddScoped<IRepository<Database>>(servicesProvider.DatabaseRepository);
My problem is that the new keyword is ignored at runtime and the executed Func is the one declared in my base class instead of the derived one.
If I do this it's working
services.AddScoped<IRepository<Database>>((servicesProvider as FooFileSystemServicesProvider).DatabaseRepository);
But I don't want to cast it as I can't know of which type my servicesProvider will finally be.
I've tried to get the type of my servicesProvider and cast it with its own type but I get compiler error because a Type variable and a Class are different.
So how can I get the good Func executed at runtime? Thanks
Ok so I finally managed to do what I want, it was actually not that hard, my main problem was to handle the fact that my Func was not a method but a delegate. I'm not used to deal with this variable type.
My code in Startup.cs remains unchanged but here is the new code of my custom ServicesProvider
public abstract class FooServicesProvider
{
public Func<IServiceProvider, IRepository<Database>> DatabaseRepository { get; protected set; }
}
public class FooFileSystemServicesProvider : FooServicesProvider
{
public FooFileSystemServicesProvider()
{
base.DatabaseRepository = GetDatabaseRepository;
}
private DatabaseFileSystemRepository GetDatabaseRepository(IServiceProvider serviceProvider)
{
//Specific code determining which database to use and create a new one if needed
//our databases are FOLDERS containing some files
//knowing how chosenDb.FullName is set is not important here
//[...]
var databaseRepository = new DatabaseFileSystemRepository(chosenDb.FullName);
databaseRepository.testProperty = "Foo value";
return databaseRepository;
}
}
Just in case people are wondering: DatabaseFileSystemRepository is a class that implements the interface IRepository<Database>>
If anyone comes up with a different solution, I'm very curious to know it.

Unity Decorator Extension fails with multiple implementations

I've been struggling with this problem for a couple days, and I still am not sure how to solve it.
I've created a container extension for the Unity Container to enable me to easily register decorator classes in the container. This is the implementation I currently have, which is almost identical to the one in this article:
public class DecoratorExtension : UnityContainerExtension
{
private int m_order;
private Dictionary<Type, IList<DecoratorRegistration>> m_typeStacks;
protected override void Initialize()
{
m_typeStacks = new Dictionary<Type, IList<DecoratorRegistration>>();
Context.Registering += AddRegistration;
Context.Strategies.Add(new DecoratorBuildStrategy(m_typeStacks), UnityBuildStage.PreCreation);
}
private void AddRegistration(object _sender, RegisterEventArgs _e)
{
if (_e.TypeFrom == null || !_e.TypeFrom.IsInterface)
return;
GetStack(_e.TypeFrom)
.Add(new DecoratorRegistration {Order = m_order++, Type = _e.TypeTo});
}
private IList<DecoratorRegistration> GetStack(Type _type)
{
if (!m_typeStacks.ContainsKey(_type))
m_typeStacks.Add(_type, new List<DecoratorRegistration>());
return m_typeStacks[_type];
}
}
What this does is use a list for each type, to store all type registrations for the same target type, so that I can reassemble it when Resolve is called, using this build strategy:
internal class DecoratorBuildStrategy : BuilderStrategy
{
private readonly Dictionary<Type, IList<DecoratorRegistration>> m_typeStacks;
internal DecoratorBuildStrategy(Dictionary<Type, IList<DecoratorRegistration>> _typeStacks)
{
m_typeStacks = _typeStacks;
}
public override void PreBuildUp(IBuilderContext _context)
{
var key = _context.OriginalBuildKey;
if (_context.GetOverriddenResolver(key.Type) != null)
return;
// Only interfaces can use decorators.
if (!key.Type.IsInterface)
return;
// Gets the list of types required to build the 'decorated' instance.
// The list is reversed so that the least dependent types are built first.
var decoratorTypes = GetDecoratorTypes(key.Type).Reverse().ToList();
if (!decoratorTypes.Any())
return;
object value = null;
foreach (var type in decoratorTypes)
{
Type typeToBuild = type;
if (typeToBuild.IsGenericTypeDefinition)
{
Type[] genericArgumentTypes = key.Type.GetGenericArguments();
typeToBuild = typeToBuild.MakeGenericType(genericArgumentTypes);
}
value = _context.NewBuildUp(new NamedTypeBuildKey(typeToBuild, key.Name));
// An Override is created so that in the next BuildUp the already
// built object gets used instead of doing the BuildUp again and
// entering an infinite loop
_context.AddResolverOverrides(new DependencyOverride(key.Type, value));
}
_context.Existing = value;
_context.BuildComplete = true;
}
private IEnumerable<Type> GetDecoratorTypes(Type _type)
{
var typeList = m_typeStacks.GetValueOrDefault(_type) ?? new List<DecoratorRegistration>(0);
if (!_type.IsGenericType)
return typeList.Select(_reg => _reg.Type);
// If the type is a generic type, we need to get all open generic registrations
// alongside the closed ones
var openGenericList = m_typeStacks
.GetValueOrDefault(_type.GetGenericTypeDefinition()) ??
new List<DecoratorRegistration>(0);
// The final result is an ordered concatenation of the closed and open registrations
// that should be used for the type
return typeList
.Concat(openGenericList)
.OrderBy(_registration => _registration.Order)
.Select(_reg => _reg.Type);
}
}
This is where the DecoratorRegistration model is used. It is just a pair of type/int that represents the order of the registration. I created this to be able to mix open and closed generic registrations correctly:
internal struct DecoratorRegistration
{
public int Order { get; set; }
public Type Type { get; set; }
}
This works wonders for the most part. The problem started when I had a class that implemented two interfaces, one which was decorated, and one that wasn't.
This is the current test case I'm trying to make work:
private interface IAny<T> {}
private interface IAnotherInterface {}
private class Base<T> : IAnotherInterface, IAny<T> {}
private class Decorator1<T> : IAny<T>
{
internal readonly IAny<T> Decorated;
public Decorator1(IAny<T> _decorated)
{
Decorated = _decorated;
}
}
[TestMethod]
public void DecoratorExtensionDoesNotInterfereWithNormalRegistrations()
{
// Arrange
var container = new UnityContainer()
.AddNewExtension<DecoratorExtension>()
.RegisterType<Base<string>>(new ContainerControlledLifetimeManager())
.RegisterType<IAny<string>, Decorator1<string>>()
.RegisterType<IAny<string>, Base<string>>()
.RegisterType<IAnotherInterface, Base<string>>();
// Act
var decorated = container.Resolve<IAny<string>>();
var normal = container.Resolve<IAnotherInterface>();
var anotherDecorated = container.Resolve<IAny<string>>();
var anotherNormal = container.Resolve<IAnotherInterface>();
// Assert
Assert.IsInstanceOfType(normal, typeof (IAnotherInterface));
Assert.IsInstanceOfType(decorated, typeof (Decorator1<string>));
Assert.AreSame(normal, anotherNormal);
Assert.AreSame(decorated, anotherDecorated);
}
This test should make my intent clear. I wanted singleton classes, but the first call to Resolve, for either IAnotherInterface or IAny<string> results in every subsequent call to return the same thing. Thus, I get an exception:
System.InvalidCastException: Unable to cast object of type 'Decorator1`1[System.String]' to type 'IAnotherInterface'.
on this line:
var normal = container.Resolve<IAnotherInterface>();
I'm not sure what to do here. I had to temporarily disable singletons in our project so that this could work as intended. What I wanted is that the Base<string> instance was a sintleton, but when I requested a IAny<string> it would create a NEW instance with the SAME base being decorated.
This is still using .Net 4.0, so I'm stuck with Unity 2.1 here (shouldn't matter in this case though).
It's been a while since I've solved this, so I figured that it would be good to replicate the answer I got from Randy Levy from the EntLib team here.
It basically boils down to the build key I was using to register the decorator instance. With my code, the instance was actually registered with the base class type, while I needed to register it with the actual decorator type.
This post has the suggested workaround for the issue, which worked very nicely on our end.
I'm not exactly sure if this is what you're looking for, but I think this does the trick in the specific case in your test:
container.RegisterType<IAny<string>, Base<string>>(
new ContainerControlledLifetimeManager(), "Inner");
container.RegisterType<IAny<string>, Decorator1<string>>(
new InjectionConstructor(
new ResolvedParameter(typeof(IAny<string>), "Inner")));
container.Register<IAnotherInterface>(new InjectionFactory(
c => c.Resolve<IAny<string>>("Inner")));
You don't need that extension for that.

StructureMap Open Generic Types

I have the following classes:
public interface IRenderer<T>
{
string Render(T obj);
}
public class Generic<T> { }
public class SampleGenericRenderer<T> : IRenderer<Generic<T>>
{
public string Render(Generic<T> obj)
{
throw new NotImplementedException();
}
}
I would like to be able to call StructureMap with
ObjectFactory.GetInstance<IRenderer<Generic<string>>>(); and receive SampleGenericRenderer<string>.
I'm currently using the following registration and receiving this error when I call GetInstance. "Unable to cast object of type:
ConsoleApplication1.SampleGenericRenderer'1[ConsoleApplication1.Generic'1[System.String]]'
to type
'ConsoleApplication1.IRenderer'1[ConsoleApplication1.Generic'1[System.String]].
public class CoreRegistry : Registry
{
public CoreRegistry()
{
Scan(assemblyScanner =>
{
assemblyScanner
.AssemblyContainingType(typeof(IRenderer<>));
assemblyScanner.AddAllTypesOf(typeof(IRenderer<>));
assemblyScanner
.ConnectImplementationsToTypesClosing(
typeof(IRenderer<>));
});
}
}
Is there any way to configure StructureMap so that it creates SampleGenericRenderer<string> instead of SampleGenericRenderer<Generic<string>>?
UPDATE: I ended up doing the type construction myself for this subset of dependencies. Because they combine contextual binding with a lot of unsupported generic bindings, this turned out to be the cleanest solution.
As Pete explained, there is probably no way with StructureMap to do this. Other DI containers might yield more success, but not all contains have great support for more complex generic trickery. The only one I know for sure that allows you to do this is the Simple Injector. With the Simple Injector, you just need the following configuration:
var container = new Container();
container.Register(typeof(IRenderer<>), typeof(SampleGenericRenderer<>));
// Usage
var renderer = container.GetInstance<IRenderer<Generic<string>>>();
renderer.Render(new Generic<string>());
More info about this method can be found here.
I don't believe StructureMap has any mechanism for closing an inner generic parameter like this.
It's not ideal, but you might try creating your own IRegistrationConvention and whenever encountering a type that is a closed type of Generic<>, do the following:
var generic_t = typeof(Generic<>).MakeGenericType(type);
var sample_renderer_t = typeof(SampleGenericRenderer<>).MakeGenericType(type);
var renderer_t = typeof(IRenderer<>).MakeGenericType(generic_t);
graph.AddType(renderer_t, sample_renderer_t);
See http://docs.structuremap.net/ScanningAssemblies.htm#section11 for more details.
For me this works:
class Program
{
static void Main()
{
ObjectFactory.Configure(x=>x.AddRegistry<CoreRegistry>());
var instance = ObjectFactory.GetInstance(typeof(IRenderer<string>)) as IRenderer<Generic<string>>;
var render = instance.Render(new Generic<string>());
}
}
This throws an exception:
ObjectFactory.GetInstance<IRenderer<Generic<string>>>();
What is your real problem?
EDIT:
Under some circumstances this could work too (If you don't know Generic<string> at design time):
static void Main()
{
ObjectFactory.Configure(x => x.AddRegistry<CoreRegistry>());
var instance = ObjectFactory.GetInstance(typeof(IRenderer<string>));
var methodInfo = instance.GetType().GetMethod("Render");
methodInfo.Invoke(instance, new[] { new Generic<string>() });
}

Correct Way to Load Assembly, Find Class and Call Run() Method

Sample console program.
class Program
{
static void Main(string[] args)
{
// ... code to build dll ... not written yet ...
Assembly assembly = Assembly.LoadFile(#"C:\dyn.dll");
// don't know what or how to cast here
// looking for a better way to do next 3 lines
IRunnable r = assembly.CreateInstance("TestRunner");
if (r == null) throw new Exception("broke");
r.Run();
}
}
I want to dynamically build an assembly (.dll), and then load the assembly, instantiate a class, and call the Run() method of that class. Should I try casting the TestRunner class to something? Not sure how the types in one assembly (dynamic code) would know about my types in my (static assembly / shell app). Is it better to just use a few lines of reflection code to call Run() on just an object? What should that code look like?
UPDATE:
William Edmondson - see comment
Use an AppDomain
It is safer and more flexible to load the assembly into its own AppDomain first.
So instead of the answer given previously:
var asm = Assembly.LoadFile(#"C:\myDll.dll");
var type = asm.GetType("TestRunner");
var runnable = Activator.CreateInstance(type) as IRunnable;
if (runnable == null) throw new Exception("broke");
runnable.Run();
I would suggest the following (adapted from this answer to a related question):
var domain = AppDomain.CreateDomain("NewDomainName");
var t = typeof(TypeIWantToLoad);
var runnable = domain.CreateInstanceFromAndUnwrap(#"C:\myDll.dll", t.Name) as IRunnable;
if (runnable == null) throw new Exception("broke");
runnable.Run();
Now you can unload the assembly and have different security settings.
If you want even more flexibility and power for dynamic loading and unloading of assemblies, you should look at the Managed Add-ins Framework (i.e. the System.AddIn namespace). For more information, see this article on Add-ins and Extensibility on MSDN.
If you do not have access to the TestRunner type information in the calling assembly (it sounds like you may not), you can call the method like this:
Assembly assembly = Assembly.LoadFile(#"C:\dyn.dll");
Type type = assembly.GetType("TestRunner");
var obj = Activator.CreateInstance(type);
// Alternately you could get the MethodInfo for the TestRunner.Run method
type.InvokeMember("Run",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
obj,
null);
If you have access to the IRunnable interface type, you can cast your instance to that (rather than the TestRunner type, which is implemented in the dynamically created or loaded assembly, right?):
Assembly assembly = Assembly.LoadFile(#"C:\dyn.dll");
Type type = assembly.GetType("TestRunner");
IRunnable runnable = Activator.CreateInstance(type) as IRunnable;
if (runnable == null) throw new Exception("broke");
runnable.Run();
I'm doing exactly what you're looking for in my rules engine, which uses CS-Script for dynamically compiling, loading, and running C#. It should be easily translatable into what you're looking for, and I'll give an example. First, the code (stripped-down):
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using CSScriptLibrary;
namespace RulesEngine
{
/// <summary>
/// Make sure <typeparamref name="T"/> is an interface, not just any type of class.
///
/// Should be enforced by the compiler, but just in case it's not, here's your warning.
/// </summary>
/// <typeparam name="T"></typeparam>
public class RulesEngine<T> where T : class
{
public RulesEngine(string rulesScriptFileName, string classToInstantiate)
: this()
{
if (rulesScriptFileName == null) throw new ArgumentNullException("rulesScriptFileName");
if (classToInstantiate == null) throw new ArgumentNullException("classToInstantiate");
if (!File.Exists(rulesScriptFileName))
{
throw new FileNotFoundException("Unable to find rules script", rulesScriptFileName);
}
RulesScriptFileName = rulesScriptFileName;
ClassToInstantiate = classToInstantiate;
LoadRules();
}
public T #Interface;
public string RulesScriptFileName { get; private set; }
public string ClassToInstantiate { get; private set; }
public DateTime RulesLastModified { get; private set; }
private RulesEngine()
{
#Interface = null;
}
private void LoadRules()
{
if (!File.Exists(RulesScriptFileName))
{
throw new FileNotFoundException("Unable to find rules script", RulesScriptFileName);
}
FileInfo file = new FileInfo(RulesScriptFileName);
DateTime lastModified = file.LastWriteTime;
if (lastModified == RulesLastModified)
{
// No need to load the same rules twice.
return;
}
string rulesScript = File.ReadAllText(RulesScriptFileName);
Assembly compiledAssembly = CSScript.LoadCode(rulesScript, null, true);
#Interface = compiledAssembly.CreateInstance(ClassToInstantiate).AlignToInterface<T>();
RulesLastModified = lastModified;
}
}
}
This will take an interface of type T, compile a .cs file into an assembly, instantiate a class of a given type, and align that instantiated class to the T interface. Basically, you just have to make sure the instantiated class implements that interface. I use properties to setup and access everything, like so:
private RulesEngine<IRulesEngine> rulesEngine;
public RulesEngine<IRulesEngine> RulesEngine
{
get
{
if (null == rulesEngine)
{
string rulesPath = Path.Combine(Application.StartupPath, "Rules.cs");
rulesEngine = new RulesEngine<IRulesEngine>(rulesPath, typeof(Rules).FullName);
}
return rulesEngine;
}
}
public IRulesEngine RulesEngineInterface
{
get { return RulesEngine.Interface; }
}
For your example, you want to call Run(), so I'd make an interface that defines the Run() method, like this:
public interface ITestRunner
{
void Run();
}
Then make a class that implements it, like this:
public class TestRunner : ITestRunner
{
public void Run()
{
// implementation goes here
}
}
Change the name of RulesEngine to something like TestHarness, and set your properties:
private TestHarness<ITestRunner> testHarness;
public TestHarness<ITestRunner> TestHarness
{
get
{
if (null == testHarness)
{
string sourcePath = Path.Combine(Application.StartupPath, "TestRunner.cs");
testHarness = new TestHarness<ITestRunner>(sourcePath , typeof(TestRunner).FullName);
}
return testHarness;
}
}
public ITestRunner TestHarnessInterface
{
get { return TestHarness.Interface; }
}
Then, anywhere you want to call it, you can just run:
ITestRunner testRunner = TestHarnessInterface;
if (null != testRunner)
{
testRunner.Run();
}
It would probably work great for a plugin system, but my code as-is is limited to loading and running one file, since all of our rules are in one C# source file. I would think it'd be pretty easy to modify it to just pass in the type/source file for each one you wanted to run, though. You'd just have to move the code from the getter into a method that took those two parameters.
Also, use your IRunnable in place of ITestRunner.
You will need to use reflection to get the type "TestRunner". Use the Assembly.GetType method.
class Program
{
static void Main(string[] args)
{
Assembly assembly = Assembly.LoadFile(#"C:\dyn.dll");
Type type = assembly.GetType("TestRunner");
var obj = (TestRunner)Activator.CreateInstance(type);
obj.Run();
}
}
When you build your assembly, you can call AssemblyBuilder.SetEntryPoint, and then get it back from the Assembly.EntryPoint property to invoke it.
Keep in mind you'll want to use this signature, and note that it doesn't have to be named Main:
static void Run(string[] args)

Categories

Resources