Saul Goodman
Saul Goodman

Reputation: 191

Missing assembly references in dynamically compiled code

Thanks for the messages about my first post about this problem. I will do a repost and try to be more clear this time. I guess this may be a trivial problem but I'm really stuck and need some help. This is my first time posting here.

using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
namespace DynamicCode
{
public class DynaCore
{
string WorkingCode = 
    "using System;"+
    "using System.Collections.Generic;"+
    "namespace DynaCore"+
    "{"+
    "   public class DynaCore"+
    "   {"+
    "       static public string DynamicResult()"+
    "       {"+
    "           return \"I'm compiled\";"+
    "       }"+
    "   }"+
    "}";


string PredicateTemplCode = 
    "using System;"+
    "using System.Linq;"+
    "using System.Collections.Generic;"+
    "namespace DynaCore"+
    "{"+
    "   public class DynaCore"+
    "   {"+
    "       static public Func<{1}, bool> DynamicResult()"+
    "       {"+
    "           return new Func<{1}, bool>({2});"+
    "       }"+
    "   }"+
    "}";

public DynaCore()
{
    string compiledString = WorkingCompilation(WorkingCode);
    Func<bool, bool> compiladePredicate = NotWorkingCompilation<bool>(PredicateTemplCode, "(o)=> true");
}

string WorkingCompilation(string code)
{
    var cParams = new CompilerParameters();
    cParams.GenerateInMemory = true;
    cParams.TreatWarningsAsErrors = false;
    cParams.GenerateExecutable = false;
    cParams.CompilerOptions = "/optimize /target:library";

    var curAss = Assembly.GetExecutingAssembly();

    cParams.ReferencedAssemblies.Add("System.dll");
    cParams.ReferencedAssemblies.Add("mscorlib.dll");
    cParams.ReferencedAssemblies.Add("System.dll");
    cParams.ReferencedAssemblies.Add("System.Data.dll");
    cParams.ReferencedAssemblies.Add(curAss.Location);

    var provider = new CSharpCodeProvider();

    var compalerResult = provider.CompileAssemblyFromSource(cParams, code);

    if (compalerResult.Errors.HasErrors)
    {
        var complieError = "";
        foreach (CompilerError ce in compalerResult.Errors)
            complieError += ce + " ";

        throw new Exception(complieError.Trim());
    }

    Module module = compalerResult.CompiledAssembly.GetModules()[0];
    Type mt = null;
    MethodInfo methInfo = null;

    return (string)module.GetType("DynaCore.DynaCore").GetMethod("DynamicResult").Invoke(null, null);
}


Func<T, bool> NotWorkingCompilation<T>(string code, string predicateString)
{
    var cParams = new CompilerParameters();
    cParams.GenerateInMemory = true;
    cParams.TreatWarningsAsErrors = false;
    cParams.GenerateExecutable = false;
    cParams.CompilerOptions = "/optimize /target:library";

    var curAss = Assembly.GetExecutingAssembly();

    cParams.ReferencedAssemblies.Add("System.dll");
    cParams.ReferencedAssemblies.Add("mscorlib.dll");
    cParams.ReferencedAssemblies.Add("System.dll");
    cParams.ReferencedAssemblies.Add("System.Data.dll");
    cParams.ReferencedAssemblies.Add("System.Core.dll");
    cParams.ReferencedAssemblies.Add(curAss.Location);

    var provider = new CSharpCodeProvider();

    var codeToRun = code.Replace("{1}", typeof(T).Name).Replace("{2}", predicateString);
    var compalerResult = provider.CompileAssemblyFromSource(cParams, codeToRun);

    if (compalerResult.Errors.HasErrors)
    {
        var complieError = "";
        foreach (CompilerError ce in compalerResult.Errors)
            complieError += ce + " ";

        throw new Exception(complieError.Trim());
    }

    Module module = compalerResult.CompiledAssembly.GetModules()[0];
    Type mt = null;
    MethodInfo methInfo = null;

    return (Func<T, bool>)module.GetType("DynaCore.DynaCore").GetMethod("DynamicResult").Invoke(null, null);
}
}
}

The problem is that when I reference System.Core.dll in ReferencedAssemblies.Add("System.Core.dll"), it gives me a compiler error:

error CS0006: Metadata file 'System.Core.dll' could not be found

I'm using v3.5 and VS 2008.

Upvotes: 9

Views: 16030

Answers (5)

Starina
Starina

Reputation: 103

Sometimes you need to add the referenced assembly to the CSharpCodeProvider parameters.

parameters.ReferencedAssemblies.Add("System.dll");

Hope this helps.

Upvotes: 1

Saul Goodman
Saul Goodman

Reputation: 191

Thanks for all the answers!

It turns out that CSharpCodeProvider defaults to version 2.0 that have no support for generics or linq. The following fixed the problem:

var provider = new CSharpCodeProvider(
    new Dictionary<String, String>{{ "CompilerVersion","v3.5" }});

Upvotes: 10

Rob
Rob

Reputation: 107

I thought I'd update this thread since it was never properly answered. I just came across the same issue (CS0006), having to include a WPF library that was in the WPF directory, and wound up fixing it with the following:

            string ver = string.Format("{0}.{1}.{2}", Environment.Version.Major, Environment.Version.MajorRevision, Environment.Version.Build);
            string exWpfDir = string.Format(@"C:\WINDOWS\Microsoft.NET\Framework\v{0}\WPF", ver);
            string exDir = string.Format(@"C:\WINDOWS\Microsoft.NET\Framework\v{0}", ver);

            CSharpCodeProvider provider = new CSharpCodeProvider();
            ICodeCompiler compiler = provider.CreateCompiler();
            CompilerParameters compilerparams = new CompilerParameters();
            compilerparams.GenerateExecutable = false;
            compilerparams.GenerateInMemory = true;
            compilerparams.IncludeDebugInformation = false;
            compilerparams.TreatWarningsAsErrors = false;
            compilerparams.CompilerOptions = string.Format("/lib:{0}", exWpfDir);
            compilerparams.CompilerOptions = string.Format("/lib:{0}", exDir);

Upvotes: 6

Judah Gabriel Himango
Judah Gabriel Himango

Reputation: 60051

Another issue may be that System.Core.dll is actually in a different location than the other dlls mentioned.

On my machine, System.Core.dll is located in %ProgramFiles%\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll, whereas the other dlls are in the GAC.

Upvotes: 2

Albin Sunnanbo
Albin Sunnanbo

Reputation: 47058

The resulting code

using System;
using System.Linq;
using System.Collections.Generic;
namespace DynaCore
{
    public class DynaCore
    {
        static public Func<Boolean, bool> Main()
        {
            Func<Boolean, bool> retur = (o) => true;
        }
    }
}

does not compile itself when pasted into a new file. First compilation error is

'DynaCore.DynaCore.Main()': not all code paths return a value

First you need to generate code thats compiling when pasted into a empty .cs file.

The first obvious thing is to fix the func-statement into something like

return new Func<Boolean, bool>(o => true);

Edit:
And don't call the method Main.

Upvotes: 0

Related Questions