How to pass dynamic classes to a generic function? - c#

I want to make a machine learning api for use with a web application, the field names will be passed to the api with their data types.
Currently I am making a class at runtime with the code provided in this answer: https://stackoverflow.com/a/3862241
The problem arises when I need to call the ML.NET PredictionFunction, I can't pass in the types for the generic function since they are made at runtime.
I've tried using reflection to call it however it seems to not be able to find the function.
NOTE: Right now the docs for ML.NET is being updated for 0.9.0 so it is unavailable.
What I've tried is this (minimal):
Type[] typeArgs = { generatedType, typeof(ClusterPrediction) };
object[] parametersArray = { mlContext }; // value
MethodInfo method = typeof(TransformerChain).GetMethod("MakePredictionFunction");
if (method == null) { // Using PredictionFunctionExtensions helps here
Console.WriteLine("Method not found!");
}
MethodInfo generic = method.MakeGenericMethod(typeArgs);
var temp = generic.Invoke(model, parametersArray);
The full (revised and trimmed) source (for more context):
Program.cs
namespace Generic {
class Program {
public class GenericData {
public float SepalLength;
public float SepalWidth;
public float PetalLength;
public float PetalWidth;
}
public class ClusterPrediction {
public uint PredictedLabel;
public float[] Score;
}
static void Main(string[] args) {
List<Field> fields = new List<Field>() {
new Field(){ name="SepalLength", type=typeof(float)},
new Field(){ name="SepalWidth", type=typeof(float)},
new Field(){ name="PetalLength", type=typeof(float)},
new Field(){ name="PetalWidth", type=typeof(float)},
};
var generatedType = GenTypeBuilder.CompileResultType(fields);
var mlContext = new MLContext(seed: 0);
TextLoader textLoader = mlContext.Data.TextReader(new TextLoader.Arguments() {
Separator = ",",
Column = new[]
{
new TextLoader.Column("SepalLength", DataKind.R4, 0),
new TextLoader.Column("SepalWidth", DataKind.R4, 1),
new TextLoader.Column("PetalLength", DataKind.R4, 2),
new TextLoader.Column("PetalWidth", DataKind.R4, 3)
}
});
IDataView dataView = textLoader.Read(Path.Combine(Environment.CurrentDirectory, "Data", "flowers.txt"););
var pipeline = mlContext.Transforms
.Concatenate("Features", "SepalLength", "SepalWidth", "PetalLength", "PetalWidth")
.Append(mlContext.Clustering.Trainers.KMeans("Features", clustersCount: 3));
var model = pipeline.Fit(dataView);
Type[] typeArgs = { generatedType, typeof(ClusterPrediction) };
object[] parametersArray = { mlContext }; // value
MethodInfo method = typeof(TransformerChain).GetMethod("MakePredictionFunction");
if (method == null) { // Using PredictionFunctionExtensions helps here
Console.WriteLine("Method not found!");
}
MethodInfo generic = method.MakeGenericMethod(typeArgs);
var temp = generic.Invoke(model, parametersArray);
var prediction = temp.Predict(new GenericData {SepalLength = 5.6f, SepalWidth = 2.5f,
PetalLength = 3.9f, PetalWidth = 1.1f});
}
}
}

Try reading your test data in an IDataView, than pass that IDataView to model.Transform();
That should insert the Score and the PredictedLabel as separate columns in your test data.

It seems, when trying to reflect for the MakePredictionFunction, you confused the TransformerChain<TLastTransformer> type (which is an instantiable generic type) with the static class TransformerChain.
But even reflecting upon TransformerChain<TLastTransformer> will not succeed, because MakePredictionFunction is not a method declared by this type. Rather, MakePredictionFunction is an extension method declared in the static class PredictionFunctionExtensions⁽¹⁾.
Thus, to get the MethodInfo for MakePredictionFunction, try this:
MethodInfo method = typeof(PredictionFunctionExtensions).GetMethod("MakePredictionFunction");
⁽¹⁾
I am not 100% certain which namespace PredictionFunctionExtensions resides in. Searching the ML.NET 0.9.0 API documentation, it seems it resides in the Microsoft.ML.Runtime.Data namespace. But trying to visit the actual documentation page for MakePredictionFunction currently only results in a 404 error, so there is a chance that this information might perhaps not be accurate (i am no ML.NET user, so i can't verify) :-(

Related

XLWorkbook : hexadecimal value 0x1D is invalid character ' on memory stream saving [duplicate]

I have a C# app that exports to Excel using ClosedXML. It works fine but just ran into an issue where when i hit the :
var ms = new MemoryStream();
workbook.SaveAs(ms);
I get an exception:
' ', hexadecimal value 0x0B, is an invalid character
Its definitely data related because it I look at certain data it works fine but other data it causes this issue.
how can i figure out which character is causing the issue? Also, once I figure that out, what is the best way of finding where this character is within my data?
Since you have invalid characters in the data / strings you put into the ClosedXML sheet, you have to find them and get them out.
The simplest solution is to add
.Replace((0x0B).ToString(), " ")
to all your strings to get rid of the vertical tabs and replace them with spaces.
Since ClosedXML is an open source project, the simplest way of tracking the error down would be building it from the source *, and then running your code against the library in debug mode.
Once you see the full stack trace, you should be able to identify the spot from which the error is coming. Good chances are that it is a bug in the way the ClosedXML project uses Microsoft XML libraries, because the error that you mentioned is reported by a library outside the ClosedXML project.
* I downloaded the project, and tried building it. Everything in the closedxml-79843.zip package builds correctly.
Since ClosedXML doesn't prevent you from using the 0x0B character in values, you'll either have to scrub your data of it yourself (as suggested by #Raidri), or you could force and exception, or do a string replace when the value is set. I've created a sample program below which uses Castle's Dynamic Proxy to wrap the IXLWorksheet and IXLCell interfaces. Firstly, we proxy the IXLWorksheet values (which returned from adding a new worksheet as in the example below, or by indexing an existing worksheet). This needs to be done manually via a method call; everything else from then on is set up. When accessing cells (via the Cell methods, or the ActiveCell property) a proxied IXLCell value is returned which checks the data being set via the Value property and the SetValue method. The check is done in the ValidateMethodInterceptor as per the comments. This whole mechanism can be left in your codebase and turned on/off via a switch in the Program.Proxy method if you so desire.
As a further alternative, the package EPPlus (which has similar functionality to ClosedXML) doesn't crash when confronted with the VT character. Instead it replaces it with the value _x00B_. Perhaps a switch would be more beneficial?
internal class Program
{
private static void Main(string[] args)
{
var stream = new MemoryStream();
using (stream)
{
using (var workbook = new XLWorkbook())
{
using (var worksheet = Proxy(workbook.Worksheets.Add("Sheet 1")))
{
worksheet.Cell("A1").Value = "This is a test";
worksheet.Cell("A2").Value = "This \v is a test";
workbook.SaveAs(stream);
}
}
}
}
public static IXLWorksheet Proxy(IXLWorksheet target)
{
var generator = new ProxyGenerator();
var options = new ProxyGenerationOptions { Selector = new WorksheetInterceptorSelector() };
return generator.CreateInterfaceProxyWithTarget<IXLWorksheet>(target, options);
}
}
public class WorksheetInterceptorSelector : IInterceptorSelector
{
private static readonly MethodInfo[] methodsToAdjust;
private readonly ProxyCellInterceptor proxyCellInterceptor = new ProxyCellInterceptor();
static WorksheetInterceptorSelector()
{
methodsToAdjust = typeof(IXLWorksheet).GetMethods()
.Where(x => x.Name == "Cell")
.Union(new[] { typeof(IXLWorksheet).GetProperty("ActiveCell").GetGetMethod() })
.ToArray();
}
#region IInterceptorSelector Members
public IInterceptor[] SelectInterceptors(System.Type type, System.Reflection.MethodInfo method, IInterceptor[] interceptors)
{
if (!methodsToAdjust.Contains(method))
return interceptors;
return new IInterceptor[] { proxyCellInterceptor }.Union(interceptors).ToArray();
}
#endregion
}
public class CellInterceptorSelector : IInterceptorSelector
{
private static readonly MethodInfo[] methodsToAdjust = new[] { typeof(IXLCell).GetMethod("SetValue"), typeof(IXLCell).GetProperty("Value").GetSetMethod() };
private ValidateMethodInterceptor proxyCellInterceptor = new ValidateMethodInterceptor();
#region IInterceptorSelector Members
public IInterceptor[] SelectInterceptors(System.Type type, MethodInfo method, IInterceptor[] interceptors)
{
if (method.IsGenericMethod && method.Name == "SetValue" || methodsToAdjust.Contains(method))
return new IInterceptor[] { proxyCellInterceptor }.Union(interceptors).ToArray();
return interceptors;
}
#endregion
}
public class ProxyCellInterceptor : IInterceptor
{
#region IInterceptor Members
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
//Wrap the return value
invocation.ReturnValue = Proxy((IXLCell)invocation.ReturnValue);
}
#endregion
public IXLCell Proxy(IXLCell target)
{
var generator = new ProxyGenerator();
var options = new ProxyGenerationOptions { Selector = new CellInterceptorSelector() };
return generator.CreateInterfaceProxyWithTarget<IXLCell>(target, options);
}
}
public class ValidateMethodInterceptor : IInterceptor
{
#region IInterceptor Members
public void Intercept(IInvocation invocation)
{
var value = invocation.Arguments[0];
//Validate the data as it is being set
if (value != null && value.ToString().Contains('\v'))
{
throw new ArgumentException("Value cannot contain vertical tabs!");
}
//Alternatively, you could do a string replace:
//if (value != null && value.ToString().Contains('\v'))
//{
// invocation.Arguments[0] = value.ToString().Replace("\v", Environment.NewLine);
//}
invocation.Proceed();
}
#endregion
}

Fake calling Namespace to test reflection

I have a piece of code that gets a specific portion of the namespace from the calling assembly. Now I want to unit test this code.
Is there a way to fake the name of the calling namespace using NUnit without implementing the NUnit testcase in that particular namespace?
Here is the method I want to test:
public static string FindCallingNameSpace()
{
var stackTrace = new StackTrace();
var stackFrames = stackTrace.GetFrames();
if (stackFrames != null)
{
int nrFrames = stackFrames.Length;
for (int i = 0; i < nrFrames; i++)
{
var methodBase = stackTrace.GetFrame(i).GetMethod();
var Class = methodBase.ReflectedType;
if (Class != null && Class.Namespace != null && Class.Namespace != "Foo.Common.WebService")
{
var Namespace = Class.Namespace.Split('.');
return Namespace[1];
}
}
}
throw new Exception("Can't determine calling namespace! Need this to determine correct api url to call!");
}
An example would be:
Bar.ExampleNs.SomeMethod() calls Foo.Common.WebService.CallApi() which itself calls the method above to retrieve the namespace from SomeMethod(). The result then would be "ExampleNs".
Now is it possible to create an NUnit UnitTest that is coded in the namespace MyUnitTests.ApiTest.TestNameSpace() but inside Foo.Common.WebService the call appears to come from Bar.ExampleNs.SomeMethod() so I can test for "ExampleNs"?
I think by far the simplest way of achieving what you're after is to just create a call forwarder and call the FindCallingNamespace method via the forwarder. So, assuming that the FindCallingNamespace method is in a class CallerStuff you create this:
namespace SomeNameSpace.ToTest {
static class RemoteCaller {
static public string Run() {
return CallerStuff.FindCallingNameSpace();
}
}
}
Then in your test you call RemoteCaller.Run, rather than CallerStuff.FindCallingNamespace.
However, you mentioned having Parameterized Tests, so presumably you might end up with a few different namespaces you want to test from which would mean more remote callers in different namespaces, which got me thinking that there might be a more generic approach.
The code below, essentially creates these wrapper classes for you by compiling them on the fly and then invoking them.
class CodeMaker {
static string _codesectionOne = #"
using Foo.Common.WebService;
namespace ";
static string _codesectionTwo = #" {
class RemoteCaller {
static public string Run() {
return CallerStuff.FindCallingNameSpace();
}
}
}";
public static string CompileAndCall(string targetNamespace,
string referenceAssembly) {
CompilerParameters CompilerParams = new CompilerParameters();
string outputDirectory = Directory.GetCurrentDirectory();
CompilerParams.GenerateInMemory = true;
CompilerParams.TreatWarningsAsErrors = false;
CompilerParams.GenerateExecutable = false;
CompilerParams.CompilerOptions = "/optimize";
string[] references = { "System.dll", referenceAssembly};
CompilerParams.ReferencedAssemblies.AddRange(references);
CSharpCodeProvider provider = new CSharpCodeProvider();
var codeToCompile = _codesectionOne + targetNamespace + _codesectionTwo;
CompilerResults compile = provider.CompileAssemblyFromSource(CompilerParams,
codeToCompile);
if (compile.Errors.HasErrors) {
string text = "Compile error: ";
foreach (CompilerError ce in compile.Errors) {
text += "rn" + ce.ToString();
}
throw new Exception(text);
}
Module module = compile.CompiledAssembly.GetModules()[0];
Type mt = null;
MethodInfo methInfo = null;
if (module != null) {
mt = module.GetType(targetNamespace + ".RemoteCaller");
}
if (mt != null) {
methInfo = mt.GetMethod("Run");
}
if (methInfo != null) {
return (string)methInfo.Invoke(null, null);
}
throw new InvalidOperationException("It's all gone wrong!");
}
}
You would then invoke the method from your test:
Assert.AreEqual("Fiddle", CodeMaker.CompileAndCall("Wibble.Fiddle.Con", "SO.dll"));
Assert.AreEqual("Fuddle", CodeMaker.CompileAndCall("Wibble.Fuddle.Con", "SO.dll"));
Note, "SO.dll" in the example above is the name of the assembly containing the CallerStuff.FindCallingNamespace
Using the compiler to generate the caller classes is probably overkill for what you're after and you might have to tweak the error handling in the code if you do decide to use it. If you're invoking the generated classes multiple times from different tests, then it may also be worth caching them, possibly through a dictionary keyed off namespace rather than compiling them every time. Compile + Call code is based on this blog post by Simeon Pilgrim.

Intercepting method invocation to c# objects

I have an hybrid c# object, with some instance properties and methods, and I pass it to IronPython. What I want is to syncronize the dispatch to the c# members, both static and dynamics, from Py code.
I implemented the IDynamicMetaObjectProvider on the c# object, and I noticed that when Py invokes the static methods of my object, and with instance methods, defined at compile time vs dynamics, the method BindInvokeMember is never used, but it is always called the method BindGetMember.
I'm a little confused, probably this thing can't be done?
IronPython will always use BindGetMember and then Invoke the result because that's how Python works - get the attribute from the object, then call it. Your BindGetMember implementation should return another dynamic object that implements BindInvokeMember, which will have the arguments you need.
I also got stuck with this for a while.
The solution is to implement the BindGetMember and return an meta object whichs expression Points to a function. This Function has to return a delegate which is then called with the Parameters. So BindInvokeMember is not used at all. That worked for me. My code looks like this:
public override DynamicMetaObject BindGetMember(GetMemberBinder aBinder)
{
var aMetaObject = this;
var aIsMethod = aMetaObject.IsMethod(aBinder.Name, aBinder.IgnoreCase);
if (aIsMethod)
{
var aRestrictions = BindingRestrictions.GetTypeRestriction(this.Expression, this.LimitType);
var aThisExpression = Expression.Convert(this.Expression, this.LimitType);
var aMethodInfo = typeof(CDynamicObjectScriptAdapter).GetMethod(CDynamicObjectScriptAdapter.GetDelegate_MethodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var aParameters = new Expression[] { Expression.Constant(aBinder) };
var aCallExpression = Expression.Call(aThisExpression, aMethodInfo, aParameters);
var aResult = new DynamicMetaObject(aCallExpression, aRestrictions);
return aResult;
}
else
{
var aRestrictions = BindingRestrictions.GetTypeRestriction(this.Expression, this.LimitType);
var aThisExpression = Expression.Convert(this.Expression, this.LimitType);
var aMethodInfo = typeof(CDynamicObjectScriptAdapter).GetMethod(CDynamicObjectScriptAdapter.GetValue_MethodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var aParameters = new Expression[] { Expression.Constant(aBinder) };
var aCallExpression = Expression.Call(aThisExpression, aMethodInfo, aParameters);
var aResult = new DynamicMetaObject(aCallExpression, aRestrictions);
return aResult;
}
}
internal const string GetDelegate_MethodName = "GetDelegate";
internal object GetDelegate(GetMemberBinder aBinder)
{
var aScriptAdapter = this;
var aAdaptedObject = aScriptAdapter.AdaptedObject;
var aClassInfo = aAdaptedObject.ClassInfo;
var aIgnoreCase = aBinder.IgnoreCase;
var aCaseSensitive = !aIgnoreCase;
var aMethodInfoDic = aClassInfo.GetScriptMethodInfoDic(aCaseSensitive);
var aName = aBinder.Name;
var aScriptMethodInfo = aMethodInfoDic[aName];
var aMethodInfo = aScriptMethodInfo.MethodInfo;
var aDelegateType = aScriptMethodInfo.ScriptMethodAttribute.DelegateType;
var aDelegate = aMethodInfo.CreateDelegate(aDelegateType, aAdaptedObject);
return aDelegate;
}

Testing using reflection (PrivateObject)

I have a minor but rather annoying problem.
I am doing some tests using a PrivateObject to access various methods in a class. This all works fine. However when the method signature contains "ref" the ref keyword does not seem to have any effect.
private bool NewDeviceArrivedDeviceAtWorkcenter(ThreadStartArgs args, ref Device deviceAtStation)
{
//..SomeCode
deviceAtStation = null;
//...Method to test
}
This test is failing..
[TestMethod]
public void CheckForDeviceAtWorkcenterNoDeviceFound()
{
Initialization omitted
var device = new Device();
var result = accessor.Invoke("NewDeviceArrivedDeviceAtWorkcenter",
new []
{
typeof (ThreadStartArgs),
typeof (Device).MakeByRefType()
},
new object[]
{
threadStartArgs,
device
});
Assert.IsNull(device);
}
Question: Why is device obj in the test method not set to null?
Any help appreciated
Kind Regards
Carsten
The return is made through the argument array passed into the Invoke.
[TestMethod]
public void CheckForDeviceAtWorkcenterNoDeviceFound()
{
//Initialization omitted for publicObject, threadStartArgs, device
Type[] myTypes = new Type[] {typeof (ThreadStartArgs),
typeof (Device).MakeByRefType() };
object[] myArgs = new object[] { threadStartArgs, device };
string sMethod = "NewDeviceArrivedDeviceAtWorkcenter";
//Invoke method under test
bool bResult = (bool)publicObject.Invoke(sMethod, myTypes, myArgs);
Device returnDevice = (Device)myArgs[1];
Assert.IsNull(returnDevice);
}
According to this reply you should get the MethodInfo of the method you want to test and invoke it just with the parameters array.
Have you tried invoking the method just with typeof(Device), without the MakeByRefType() call?

How best to create and execute a method in a .NET (C#) class dynamically through configuration

I'm thinking of something along the lines of the "Inline Task" in MsBuild. For reference: http://msdn.microsoft.com/en-us/library/dd722601.aspx
I'd like to find or create a framework which allows me to override a method via configuration. For example if I have a well known base class which has a method Execute(args), how can I supply an overridden method implementation at deployment time, without requiring new code, build, release cycle? I would like to actually plug in the method body into a config file or preferably a database table.
I assume this would be done either with code dom, dynamic language integration, or perhaps something like powershell(?). I'm looking for recommendations or perhaps a library someone has already written.
The application is written in C#. Preferably the extension would also be in C#, but I'm open to other ideas as well.
Update: Technically I don't even have to actually override a method. It would be sufficient to just be able to dynamically execute some external source code, passing in an arg and returning a result.
Update. I ended up writing code to instantiate a PowerShell object and execute a script dynamically to return a value. Here is a snippet of code 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 from it. It works great. Thanks for all the responses.
Here are two examples of dynamic execution. I have used neither though so I can't comment further.
http://www.codeproject.com/KB/dotnet/evaluator.aspx
http://www.csharpfriends.com/articles/getarticle.aspx?articleid=118
Regarding 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");
One option would be to use Iron Python (or another DLR language). Your Execute method would then lookup the script in your configuration file, compile it and execute it all at runtime.
Including the necessary Iron Python assemblies with your project isn't a significant overhead.
You might need to do some plumbing to expose other parts of your application to the python runtime environment but this is quite easy to do.
You can use interfaces and then resolve the concrete classes at runtime e.g. using configuration files.
Check the various Dependency Injection Containers at http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx
Managed Extensibility Framework (MEF) might be suitable as well. It was included as part of .NET 4.
http://msdn.microsoft.com/en-us/library/dd460648.aspx
http://mef.codeplex.com/
If the extensibility is just for one method then MEF would be overkill. If what you are extending will grow over time then I think MEF would provide the most robust and long-term manageable framework.
It looks like you might want to have a look at the Factory Pattern; returning delegates. Unfortunately you will need a type to 'house' the method, so you would typically generate code like:
namespace Dynamic {
public static int Foo(int bar) {
// .. Configured body here.
}
}
It's important that your factory does not generate methods it has seen 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);
}
}

Categories