What is the best way to create and execute a method in a .NET (C #) class dynamically through configuration

I am thinking of something in the "Inline Task" build in MsBuild. For reference: http://msdn.microsoft.com/en-us/library/dd722601.aspx

I would like to find or create a framework that allows me to override a method through configuration. For example, if I have a well-known base class that has an Execute (args) method, how can I ensure that an overridden method is implemented during deployment without requiring a new code loop, build, release? I would like to actually connect the body of the method to the configuration file, or preferably to the database table.

I assume that this will be done either with dom code, or with dynamic language integration, or perhaps with something like powershell (?). I am looking for recommendations, or perhaps a library that someone has already written.

The application is written in C #. Preferably the extension will also be in C #, but I'm also open to other ideas.

Update: Technically, I don’t even need to redefine the method. It is enough just to be able to dynamically execute some external source code, pass to arg and return the result.

Update I ended up writing code to instantiate a PowerShell object and dynamically execute the script to return the value. Here is the code snippet I used.

public static Collection<PSObject> ExecuteScript(string code, string variableName, object variableValue) { PowerShell ps = PowerShell.Create(); ps.AddScript(code); if (!string.IsNullOrWhiteSpace(variableName)) { ps.Runspace.SessionStateProxy.SetVariable(variableName, variableValue); } var result = ps.Invoke(); return result; } 

Then in the calling code, I simply check the first PSObject in the return value and pull the resulting value out of it. It works great. Thanks for all the answers.

+6
source share
5 answers

One option is to use Iron Python (or another DLR language). Then your Execute method will look for a script in your configuration file, compile it, and execute it all at runtime.

Including the necessary Iron Python builds in your project is not a significant overhead.

You may need to do some plumbing to expose other parts of your application to the python runtime, but this is pretty easy to do.

+1
source

Here are two examples of dynamic execution. I have not used any of them, so I can no longer comment.

http://www.codeproject.com/KB/dotnet/evaluator.aspx
http://www.csharpfriends.com/articles/getarticle.aspx?articleid=118

As for namespaces, from the second article you can add assemblies through the CompilerParameter class.

 // Create the C# compiler CSharpCodeProvider csCompiler = new CSharpCodeProvider(); ICodeCompiler iCodeCompiler = csCompiler.CreateCompiler(); // input params for the compiler CompilerParameters compilerParams = new CompilerParameters(); compilerParams.OutputAssembly = "CSharpFriends.dll"; compilerParams.ReferencedAssemblies.Add("system.dll"); 
+2
source

You can use interfaces and then allow specific classes at runtime, for example. using configuration files. Check out various dependency injection containers http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx

+1
source

Looks like you can take a look at Factory Pattern ; return delegates. Unfortunately, you will need a type for the "home" method, so you usually generate code, for example:

 namespace Dynamic { public static int Foo(int bar) { // .. Configured body here. } } 

It is important that your factory does not generate the methods that it saw before. Here is an example:

 static class Delegates { private static Func<Func<int, string>> _test; public static Func<int, string> Test { get { return _test(); } } static Delegates() { // Use your config variables instead of the "return arg.ToString();" CreateFactory<Func<int, string>>(x => _test = x, "return arg.ToString();"); } private static void CreateFactory<TDelegate>(Action<Func<TDelegate>> locationSetter, string identifier) { locationSetter(() => { var result = Generate<TDelegate>(identifier); locationSetter(() => result); return result; }); } private static string GenerateSignature<TDelegate>() { // Create the signature of the delegate. var t = typeof(TDelegate); if (!typeof(Delegate).IsAssignableFrom(t)) throw new Exception("TDelegate must be delegate type."); var invoke = t.GetMethod("Invoke"); var sig = new StringBuilder(); // Append the return type. if (invoke.ReturnType == typeof(void)) sig.Append("void"); else sig.Append(invoke.ReturnType.FullName); sig.Append(" "); sig.Append("Invoke("); // Append the parameters. var param = invoke.GetParameters(); for (var i = 0; i < param.Length; i++) { if (i != 0) sig.Append(", "); sig.Append(param[i].ParameterType.FullName); sig.Append(" "); sig.Append(param[i].Name); } sig.Append(")"); return sig.ToString(); } private static TDelegate Generate<TDelegate>(string code) { // Generate the containing class and method. var codeBuilder = new StringBuilder(50); codeBuilder.AppendLine("using System;"); codeBuilder.Append("namespace Dynamic { class DynamicClass { public static "); codeBuilder.Append(GenerateSignature<TDelegate>()); codeBuilder.AppendLine("{"); codeBuilder.AppendLine(code); codeBuilder.AppendLine("} } }"); var compilerVersion = new Version(1, 0, 0, 0); // Create the compiler parameters. var parameters = new CompilerParameters(); parameters.GenerateInMemory = true; parameters.GenerateExecutable = false; parameters.ReferencedAssemblies.Clear(); foreach (var referenceAssembly in AppDomain.CurrentDomain.GetAssemblies()) { parameters.ReferencedAssemblies.Add(referenceAssembly.Location); // Figure out which version we are compiling against. var an = new AssemblyName(referenceAssembly.FullName); if (an.Name == "mscorlib" && compilerVersion < an.Version) { compilerVersion = an.Version; } } var cp = new CSharpCodeProvider( new Dictionary<string, string>() { { "CompilerVersion", string.Format("v{0}.{1}", compilerVersion.Major, compilerVersion.Minor) } } ); var results = cp.CompileAssemblyFromSource(parameters, codeBuilder.ToString()); if (results.Errors.HasErrors) throw new Exception("Method failed to compile."); var assembly = results.CompiledAssembly; if (assembly == null) throw new Exception("Method failed to compile."); var t = assembly.GetType("Dynamic.DynamicClass"); if (t == null) throw new Exception("Method failed to compile."); var m = t.GetMethod("Invoke"); if (m == null) throw new Exception("Method failed to compile."); return (TDelegate)(object)Delegate.CreateDelegate(typeof(TDelegate), m); } } 
+1
source

Perhaps the Managed Extensibility Framework (MEF) is also suitable. It has been included as part of .NET 4.

http://msdn.microsoft.com/en-us/library/dd460648.aspx

http://mef.codeplex.com/

If extensibility is intended for only one method, then MEF will be redundant. If what you expand grows over time, I think MEF will provide the most reliable and long-term managed infrastructure.

+1
source

Source: https://habr.com/ru/post/895680/


All Articles