Question

I compile code dynamically from code:

            string code = @"
                namespace CodeInjection
                {
                    public static class DynConcatenateString
                    {
                        public static string Concatenate(string s1, string s2){
                            return s1 + "" ! "" + s2;
                        }
                    }
                }";

            // http://stackoverflow.com/questions/604501/generating-dll-assembly-dynamically-at-run-time
            Console.WriteLine("Now doing some injection...");

            Console.WriteLine("Creating injected code in memory");


            CSharpCodeProvider codeProvider = new CSharpCodeProvider();
            ICodeCompiler icc = codeProvider.CreateCompiler();
            CompilerParameters parameters = new CompilerParameters();
            parameters.GenerateExecutable = false;
            parameters.GenerateInMemory = true;
            //parameters.OutputAssembly = "DynamicCode.dll"; // if specified creates the DLL
            CompilerResults results = icc.CompileAssemblyFromSource(parameters, code);

Then I can invoke the method with reflection:

                Console.WriteLine("Input two strings, and I will concate them with reflection:");
                var s1 = Console.ReadLine();
                var s2 = Console.ReadLine();
                var result = (string)results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString").GetMethod("Concatenate").Invoke(null, new object[] { s1, s2 });

                Console.WriteLine();
                Console.WriteLine("Result:");
                Console.WriteLine(result);

But I would like to invoke something like this:

                Console.WriteLine("Input two strings, and I will concate them with dynamic type:");
                var s1 = Console.ReadLine();
                var s2 = Console.ReadLine();

                dynamic type = results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString");
                var resultA = (string)type.Concatenate(s1, s2); // runtime error
                // OR
                var resultB = (string)CodeInjection.DynConcatenateString.Concatenate(s1, s2); // compile error (cannot find assembly)


                Console.WriteLine();
                Console.WriteLine("Result:");
                Console.WriteLine(resultA);
                Console.WriteLine(resultB);

The resultB would be better. Any ideas how to do it? I need strictly .NET 4.0, we have not updated to 4.5 yet (because the half of the team uses VS 2010). (I can invoke with reflection, I know, I am just looking for another way, because we need to test dyn. code)

Was it helpful?

Solution

You can't use dynamic directly in this scenario. dynamic always requires a class instance, but you are trying to call a method in a static class, hence you don't have a class instance.

However, you can create a helper class and use that in combination with dynamic:

public class StaticMethodInvoker : DynamicObject
{
    Type _containingType;

    public StaticMethodInvoker(Type containingType)
    {
        _containingType = containingType;
    }

    public override bool TryInvokeMember(
        InvokeMemberBinder binder, Object[] args, out Object result)
    {
        result = _containingType.InvokeMember
            binder.Name,
            BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public,
            null, null, args);
        return true;
    }
}

Usage:

var type = results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString");
dynamic DynConcatenateString = new StaticMethodInvoker(type);
string result = DynConcatenateString.Concatenate(s1, s2);

OTHER TIPS

You're calling a static method. With dynamic you bypass the check but actually you're trying to call Concatenate() on the System.Type for CodeInjection.DynConcatenateString.

First of all make it an instance method:

public class DynConcatenateString
{
    public string Concatenate(string s1, string s2){
        return s1 + "" ! "" + s2;
    }
}

Now let's see your code:

dynamic type = results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString");

This is a System.Type, not an object of type CodeInjection.DynConcatenateString. If you change dynamic to var you'll see the right type at compile time. You have then to create an instance of that type, like this:

var type = results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString");
dynamic instance = Activator.CreateInstance(type);

For the syntax B there is no hope in C# because CodeInjection.DynConcatenateString doesn't exist at compile time then that line will fail.

If you must keep it static then all you can do is to use reflection to invoke that method (dynamic is then useless). Don't worry about performance hit...DLR isn't much faster than plain Reflection (as AFAIK it's how it's implemented with a touch of caching).

Why not use generic types? Define your class interface:


    public interface IDynConcatenateString 
    {
        string Concatenate(string s1, string s2);
    }

And then generate dinamic code

    public T GetInstanceOf<T>(string code, string typename)
    {
        Console.WriteLine("Now doing some injection...");

        Console.WriteLine("Creating injected code in memory");


        CSharpCodeProvider codeProvider = new CSharpCodeProvider();
        ICodeCompiler icc = codeProvider.CreateCompiler();
        CompilerParameters parameters = new CompilerParameters();
        parameters.GenerateExecutable = false;
        parameters.GenerateInMemory = true;
        //parameters.OutputAssembly = "DynamicCode.dll"; // if specified creates the DLL
        CompilerResults results = icc.CompileAssemblyFromSource(parameters, code);

        //type name = "CodeInjection.DynConcatenateString"

        T codeclass = (T)results.CompiledAssembly.CreateInstance(typename);

        return codeclass;

    }

Try to execute like this...

public void Exec() 
    {
        string code = @"
            namespace CodeInjection
            {
                public class MyDynConcatenateString : IDynConcatenateString 
                {
                    public string Concatenate(string s1, string s2){
                        return s1 + "" ! "" + s2;
                    }
                }
            }";
        IDynConcatenateString writer = GetInstanceOf<IDynConcatenateString>(
            code, "CodeInjection.MyDynConcatenateString");

        var s1 = Console.ReadLine();
        var s2 = Console.ReadLine();
        var result = writer.Concatenate(s1, s2);

        Console.WriteLine(result);

    }

The IDynConcatenateString implementation is dynamic, defined in the "code" variable, as a parameter of Exec method. You only need to define the interface, and no need to hardcode method names or class names.

I thought this was an interesting usage, so I made a convenience version of my LateType's constructor LateType(Assembly assembly, String typename)in my open source portable library Dynamitey

dynamic DynConcatenateString = new DynamicObjects.LateType(cr.CompiledAssembly, "CodeInjection.DynConcatenateString");

Assert.That("1 ! 2", Is.EqualTo(DynConcatenateString.Concatenate("1","2")));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top