Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
472 views
in Technique[技术] by (71.8m points)

c# - Compiling code at runtime, loading into current appdomain but Type.GetType cant see it

Im compiling some code at runtime then loading the assembly into the current appdomain, however when i then try to do Type.GetType it cant find the type...

Here is how i compile the code...

public static Assembly CompileCode(string code)
    {
        Microsoft.CSharp.CSharpCodeProvider provider = new CSharpCodeProvider();
        ICodeCompiler compiler = provider.CreateCompiler();
        CompilerParameters compilerparams = new CompilerParameters();
        compilerparams.GenerateExecutable = false;
        compilerparams.GenerateInMemory = false;

        foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            try
            {
                string location = assembly.Location;
                if (!String.IsNullOrEmpty(location))
                {
                    compilerparams.ReferencedAssemblies.Add(location);
                }
            }
            catch (NotSupportedException)
            {
                // this happens for dynamic assemblies, so just ignore it. 
            }
        } 
        CompilerResults results =
           compiler.CompileAssemblyFromSource(compilerparams, code);
        if (results.Errors.HasErrors)
        {
            StringBuilder errors = new StringBuilder("Compiler Errors :
");
            foreach (CompilerError error in results.Errors)
            {
                errors.AppendFormat("Line {0},{1}: {2}
",
                       error.Line, error.Column, error.ErrorText);
            }
            throw new Exception(errors.ToString());
        }
        else
        {
            AppDomain.CurrentDomain.Load(results.CompiledAssembly.GetName());
            return results.CompiledAssembly;
        }
    }

This bit fails after getting the type from the compiled assembly just fine, it does not seem to be able to find it using Type.GetType....

Assembly assem = RuntimeCodeCompiler.CompileCode(code);
string typeName = 
      String.Format("Peverel.AppFramework.Web.GenCode.ObjectDataSourceProxy_{0}",
        safeTypeName);



Type t = assem.GetType(typeName); //This works just fine..
Type doesntWork = Type.GetType(t.AssemblyQualifiedName);
Type doesntWork2 = Type.GetType(t.Name);



....
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Found this nice bit of code that ensures no matter how you load your assembly it is always available from Type.GetType.

My class for compiling code into the current appdomain now looks like :

public static class RuntimeCodeCompiler
{
    private static volatile Dictionary<string, Assembly> cache = new Dictionary<string, Assembly>();
    private static object syncRoot = new object();
    static Dictionary<string, Assembly> assemblies = new Dictionary<string, Assembly>();
    static RuntimeCodeCompiler()
    {
        AppDomain.CurrentDomain.AssemblyLoad += (sender, e) =>
        {
            assemblies[e.LoadedAssembly.FullName] = e.LoadedAssembly;
        };
        AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
        {
            Assembly assembly = null;
            assemblies.TryGetValue(e.Name, out assembly);
            return assembly;
        };

    }


    public static Assembly CompileCode(string code)
    {

        Microsoft.CSharp.CSharpCodeProvider provider = new CSharpCodeProvider();
        ICodeCompiler compiler = provider.CreateCompiler();
        CompilerParameters compilerparams = new CompilerParameters();
        compilerparams.GenerateExecutable = false;
        compilerparams.GenerateInMemory = false;



        foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            try
            {
                string location = assembly.Location;
                if (!String.IsNullOrEmpty(location))
                {
                    compilerparams.ReferencedAssemblies.Add(location);
                }
            }
            catch (NotSupportedException)
            {
                // this happens for dynamic assemblies, so just ignore it. 
            }
        } 


        CompilerResults results =
           compiler.CompileAssemblyFromSource(compilerparams, code);
        if (results.Errors.HasErrors)
        {
            StringBuilder errors = new StringBuilder("Compiler Errors :
");
            foreach (CompilerError error in results.Errors)
            {
                errors.AppendFormat("Line {0},{1}: {2}
",
                       error.Line, error.Column, error.ErrorText);
            }
            throw new Exception(errors.ToString());
        }
        else
        {

            AppDomain.CurrentDomain.Load(results.CompiledAssembly.GetName());
            return results.CompiledAssembly;
        }

    }

    public static Assembly CompileCodeOrGetFromCache(string code,  string key)
    {
        bool exists = cache.ContainsKey(key);

        if (!exists)
        {

            lock (syncRoot)
            {
                exists = cache.ContainsKey(key);

                if (!exists)
                {
                    cache.Add(key, CompileCode(code));
                }
            }
        }

        return cache[key];
    }


}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...