internal static TemplateCompilationResult Compile( Type templateType, string templateBody, IEnumerable<string> assemblyFileNames, IEnumerable<string> namespaces, string tempDirectory) { LoadRuntimeBinder(); string className; var compileUnit = GetCodeCompileUnit(templateType, namespaces, templateBody, out className); string sourceCode; CodeDomProvider codeProvider; switch (Language) { case TemplateCompilationLanguage.CSharp: codeProvider = new CSharpCodeProvider(); break; case TemplateCompilationLanguage.VisualBasic: codeProvider = new VBCodeProvider(); break; default: throw new NotSupportedException("Language not supported."); } var builder = new StringBuilder(); using (var writer = new StringWriter(builder, CultureInfo.InvariantCulture)) { codeProvider.GenerateCodeFromCompileUnit(compileUnit, writer, new CodeGeneratorOptions()); sourceCode = builder.ToString(); } var parameters = CreateCompilerParameters(tempDirectory, assemblyFileNames); var compileResult = codeProvider.CompileAssemblyFromDom(parameters, compileUnit); if (compileResult.Errors != null && compileResult.Errors.Count > 0) throw new TemplateCompilationException(compileResult.Errors, sourceCode, templateBody); var fullClassName = TEMPLATES_NAMESPACE + "." + className; return new TemplateCompilationResult { Type = compileResult.CompiledAssembly.GetType(fullClassName), SourceCode = sourceCode }; }
/// <summary> /// Generates VB text from a compile unit and writes it to a text writer with the given options. /// </summary> /// <param name="compileUnit">The compile unit to generate text from.</param> /// <param name="writer">The text writer to write to.</param> /// <param name="options">The generation options.</param> public static void GenerateVBTo(this CodeCompileUnit compileUnit, TextWriter writer, CodeGeneratorOptions options) { using (var provider = new VBCodeProvider()) { provider.GenerateCodeFromCompileUnit(compileUnit, writer, options); } }
static void Main(string[] args) { #region Declare CodeDOM graph objects CodeCompileUnit codeCompileUnit = null; ; CodeNamespace codeNameSpace = null; CodeNamespaceImport codeNameSpaceImport = null; CodeCommentStatement codeCommentStatement = null; CodeTypeDeclaration codeTypeDeclaration = null; CodeRegionDirective codeRegionDirectiveStart = null; CodeRegionDirective codeRegionDirectiveEnd = null; CodeMemberProperty codeMemberProperty = null; CodeMemberMethod codeMemberMethod = null; CodeParameterDeclarationExpression codeParameterDeclarationExpression = null; CodeMethodReturnStatement codeMethodReturnStatement = null; CodeMemberField codeMemberField = null; CodeFieldReferenceExpression codeFieldReferenceExpression = null; CodeAssignStatement codeAssignStatement = null; CodeMethodInvokeExpression codeMethodInvokeExpression = null; CodeTryCatchFinallyStatement codeTryCatchFinallyStatement = null; CodeThrowExceptionStatement codeThrowExceptionStatement = null; CodeCatchClause codeCatchClause = null; CodeConstructor codeConstructor = null; CodeBaseReferenceExpression codeBaseReferenceExpression = null; CodeSnippetExpression codeSnippetExpression = null; #endregion #region Create Code Compile Unit codeCompileUnit = new CodeCompileUnit(); #endregion #region Create Namespace codeNameSpace = new CodeNamespace("MyCodeDOMNamespace"); codeCompileUnit.Namespaces.Add(codeNameSpace); #endregion #region Create Imports/Using codeNameSpaceImport = new CodeNamespaceImport() { Namespace = "System" }; codeNameSpace.Imports.Add(codeNameSpaceImport); codeNameSpaceImport = new CodeNamespaceImport() { Namespace = "System.IO" }; codeNameSpace.Imports.Add(codeNameSpaceImport); codeNameSpaceImport = new CodeNamespaceImport() { Namespace = "System.Collections" }; codeNameSpace.Imports.Add(codeNameSpaceImport); codeNameSpaceImport = new CodeNamespaceImport() { Namespace = "System.Collections.Generic" }; codeNameSpace.Imports.Add(codeNameSpaceImport); codeNameSpaceImport = new CodeNamespaceImport() { Namespace = "System.Linq" }; codeNameSpace.Imports.Add(codeNameSpaceImport); codeNameSpaceImport = new CodeNamespaceImport() { Namespace = "GenerateCode" }; codeNameSpace.Imports.Add(codeNameSpaceImport); #endregion #region Create Comments codeCommentStatement = new CodeCommentStatement(); codeCommentStatement.Comment = new CodeComment() { Text = "This is a regular comment", DocComment = false }; codeNameSpace.Comments.Add(codeCommentStatement); codeCommentStatement = new CodeCommentStatement(); codeCommentStatement.Comment = new CodeComment() { Text = "This is a documentation comment", DocComment = true }; codeNameSpace.Comments.Add(codeCommentStatement); #endregion #region Create Interface Type //you do not need an interface codeTypeDeclaration = new CodeTypeDeclaration() { Name = "IMyType", TypeAttributes = TypeAttributes.Public, IsClass = false, IsEnum = false, IsInterface = true, IsPartial = false, IsStruct = false }; codeNameSpace.Types.Add(codeTypeDeclaration); #endregion #region Create Region for Interface //note: region is one of the few directives supported //generally regions are used for conditional compilation issues //since the code is being generated dynamically, //just generate the code you want and don't work about directives codeRegionDirectiveStart = new CodeRegionDirective(CodeRegionMode.Start, "Start IMyType"); codeRegionDirectiveEnd = new CodeRegionDirective(CodeRegionMode.End, "Start IMyType"); codeTypeDeclaration.StartDirectives.Add(codeRegionDirectiveStart); codeTypeDeclaration.EndDirectives.Add(codeRegionDirectiveEnd); #endregion #region create property declaration for interface codeMemberProperty = new CodeMemberProperty() { Name = "MyProperty", Type = new CodeTypeReference(typeof(string)), HasGet = true, HasSet = true }; codeTypeDeclaration.Members.Add(codeMemberProperty); #endregion #region create method decalration for interface codeMemberMethod = new CodeMemberMethod() { Name = "MyMethod", ReturnType = new CodeTypeReference(typeof(int)) }; codeParameterDeclarationExpression = new CodeParameterDeclarationExpression() { Name = "MyParameter", Type = new CodeTypeReference(typeof(string)) }; codeMemberMethod.Parameters.Add(codeParameterDeclarationExpression); codeTypeDeclaration.Members.Add(codeMemberMethod); #endregion #region Create Class that implements an Interface //you do not need to implement an interface just create the class codeTypeDeclaration = new CodeTypeDeclaration() { Name = "MyBaseType", TypeAttributes = TypeAttributes.Public, IsClass = true, IsEnum = false, IsInterface = false, IsPartial = false, IsStruct = false }; codeTypeDeclaration.BaseTypes.Add("IMyType"); codeNameSpace.Types.Add(codeTypeDeclaration); #endregion #region create constructor for class codeConstructor = new CodeConstructor() { Attributes = MemberAttributes.Public }; codeParameterDeclarationExpression = new CodeParameterDeclarationExpression() { Name = "MyParameter", Type = new CodeTypeReference(typeof(string)) }; codeConstructor.Parameters.Add(codeParameterDeclarationExpression); codeAssignStatement = new CodeAssignStatement() { Left = new CodePropertyReferenceExpression() { TargetObject = new CodeThisReferenceExpression(), PropertyName = "MyProperty" }, Right = new CodeFieldReferenceExpression() { FieldName = "MyParameter" } }; codeConstructor.Statements.Add(codeAssignStatement); codeTypeDeclaration.Members.Add(codeConstructor); #endregion #region create property declaration for the class that implements the interface //for some reason default getters and setters were not implemented in codedom codeMemberField = new CodeMemberField() { Name = "_MyProperty", Type = new CodeTypeReference(typeof(string)), Attributes = MemberAttributes.Private }; codeTypeDeclaration.Members.Add(codeMemberField); codeMemberProperty = new CodeMemberProperty() { Name = "MyProperty", Type = new CodeTypeReference(typeof(string)), Attributes = MemberAttributes.Public, HasGet = true, HasSet = true }; codeFieldReferenceExpression = new CodeFieldReferenceExpression() { TargetObject = new CodeThisReferenceExpression(), FieldName = "_MyProperty" }; codeMethodReturnStatement = new CodeMethodReturnStatement() { Expression = codeFieldReferenceExpression }; codeMemberProperty.GetStatements.Add(codeMethodReturnStatement); codeAssignStatement = new CodeAssignStatement() { Left = new CodeFieldReferenceExpression() { TargetObject = new CodeThisReferenceExpression(), FieldName = "_MyProperty" }, Right = new CodeFieldReferenceExpression() { TargetObject = null, FieldName = "value" } }; codeMemberProperty.SetStatements.Add(codeAssignStatement); codeTypeDeclaration.Members.Add(codeMemberProperty); #endregion #region create method decalration for the class that implements the interface codeMemberMethod = new CodeMemberMethod() { Name = "MyMethod", ReturnType = new CodeTypeReference(typeof(int)), Attributes = MemberAttributes.Public, }; codeMemberMethod.ImplementationTypes.Add("IMytype"); codeParameterDeclarationExpression = new CodeParameterDeclarationExpression() { Name = "MyParameter", Type = new CodeTypeReference(typeof(string)) }; codeMemberMethod.Parameters.Add(codeParameterDeclarationExpression); codeTryCatchFinallyStatement = new CodeTryCatchFinallyStatement(); codeMethodInvokeExpression = new CodeMethodInvokeExpression() { Method = new CodeMethodReferenceExpression() { TargetObject = new CodeTypeReferenceExpression() { Type = new CodeTypeReference(typeof(int)) }, MethodName = "Parse" } }; codeMethodInvokeExpression.Parameters.Add(new CodeFieldReferenceExpression() { FieldName = "MyParameter" }); codeMethodReturnStatement = new CodeMethodReturnStatement(); codeMethodReturnStatement.Expression = codeMethodInvokeExpression; codeTryCatchFinallyStatement.TryStatements.Add(codeMethodReturnStatement); codeThrowExceptionStatement = new CodeThrowExceptionStatement() { ToThrow = new CodeFieldReferenceExpression() { FieldName = "ex" } }; codeCatchClause = new CodeCatchClause() { CatchExceptionType = new CodeTypeReference(typeof(System.Exception)), LocalName = "ex", }; codeCatchClause.Statements.Add(codeThrowExceptionStatement); codeTryCatchFinallyStatement.CatchClauses.Add(codeCatchClause); codeMemberMethod.Statements.Add(codeTryCatchFinallyStatement); codeTypeDeclaration.Members.Add(codeMemberMethod); #endregion #region Create Region for Class codeRegionDirectiveStart = new CodeRegionDirective(CodeRegionMode.Start, "Start MyBaseType"); codeRegionDirectiveEnd = new CodeRegionDirective(CodeRegionMode.End, "Start MyBaseType"); codeTypeDeclaration.StartDirectives.Add(codeRegionDirectiveStart); codeTypeDeclaration.EndDirectives.Add(codeRegionDirectiveEnd); #endregion #region create class that inherits a base clase codeTypeDeclaration = new CodeTypeDeclaration() { Name = "MyType", TypeAttributes = TypeAttributes.Public, IsClass = true, IsEnum = false, IsInterface = false, IsPartial = false, IsStruct = false }; codeTypeDeclaration.BaseTypes.Add("MyBaseType"); codeNameSpace.Types.Add(codeTypeDeclaration); #endregion #region create constructor for class codeConstructor = new CodeConstructor() { Attributes = MemberAttributes.Public }; codeParameterDeclarationExpression = new CodeParameterDeclarationExpression() { Name = "MyParameter", Type = new CodeTypeReference(typeof(string)) }; codeConstructor.Parameters.Add(codeParameterDeclarationExpression); codeFieldReferenceExpression = new CodeFieldReferenceExpression() { FieldName = "MyParameter" }; codeConstructor.BaseConstructorArgs.Add(codeFieldReferenceExpression); codeTypeDeclaration.Members.Add(codeConstructor); #endregion #region create method that uses the current assembly codeMemberMethod = new CodeMemberMethod() { Name = "GetDataFromCurrentlyExecutingAssembly", Attributes = MemberAttributes.Public, ReturnType = new CodeTypeReference(typeof(void)) }; codeMethodInvokeExpression = new CodeMethodInvokeExpression() { Method = new CodeMethodReferenceExpression() { TargetObject = new CodeTypeReferenceExpression() { Type = new CodeTypeReference(typeof(Console)) }, MethodName = "WriteLine" } }; //sometimes you can cheat and just add the code codeSnippetExpression = new CodeSnippetExpression() { Value = @" CurrentlyExecutingAssemblyClass currentlyExecutingAssemblyClass=new CurrentlyExecutingAssemblyClass(""Hello World""); Console.WriteLine(currentlyExecutingAssemblyClass.CurrentlyExecutingProperty); " }; codeMemberMethod.Statements.Add(codeSnippetExpression); codeTypeDeclaration.Members.Add(codeMemberMethod); #endregion #region Create Region for Class codeRegionDirectiveStart = new CodeRegionDirective(CodeRegionMode.Start, "Start MyType"); codeRegionDirectiveEnd = new CodeRegionDirective(CodeRegionMode.End, "Start MyType"); codeTypeDeclaration.StartDirectives.Add(codeRegionDirectiveStart); codeTypeDeclaration.EndDirectives.Add(codeRegionDirectiveEnd); #endregion #region render code string sourceCS = string.Empty; StringBuilder stringBuilder = new StringBuilder(); CodeDomProvider codeDomProvider = null; //Bracing style Block->same line C->new line //GenerateCodeFromCompileUnit reserves the right to rearrange your code the way it knows best CodeGeneratorOptions codeGeneratorOptions = new CodeGeneratorOptions() { BracingStyle = "C", VerbatimOrder = false, BlankLinesBetweenMembers = true, ElseOnClosing = false }; //in c# using (StringWriter stringWriter = new StringWriter()) { codeDomProvider = new CSharpCodeProvider(); codeDomProvider.GenerateCodeFromCompileUnit(codeCompileUnit, stringWriter, codeGeneratorOptions); sourceCS = stringWriter.ToString(); } //in visualbasic string sourceVB = string.Empty; using (StringWriter stringWriter = new StringWriter()) { codeDomProvider = new VBCodeProvider(); codeDomProvider.GenerateCodeFromCompileUnit(codeCompileUnit, stringWriter, codeGeneratorOptions); sourceVB = stringWriter.ToString(); } //output source //Console.WriteLine(sourceCS); //Console.ReadLine(); //Console.WriteLine(sourceVB); //Console.ReadLine(); #endregion #region declare compiler objects CompilerParameters compilerParameters = null; CompilerResults compilerResults = null; int lineNumber = 0; #endregion #region compile CS source CSharpCodeProvider csharpCodeProvider = null; Console.WriteLine("Compiling CSharp:"); foreach (string sourceLine in sourceCS.Split('\r')) { Console.WriteLine(string.Format("{0}:{1}", ++lineNumber, sourceLine.Replace("\n", ""))); } csharpCodeProvider = new CSharpCodeProvider(); compilerParameters = new CompilerParameters() { GenerateExecutable = false, GenerateInMemory = true, IncludeDebugInformation = true }; compilerParameters.ReferencedAssemblies.Add("System.dll"); compilerParameters.ReferencedAssemblies.Add("System.Linq.dll"); //reference currently executing assembly compilerParameters.ReferencedAssemblies.Add(System.Reflection.Assembly.GetExecutingAssembly().Location); compilerResults = null; //compilerResults = csharCodeProvider.CompileAssemblyFromDom(compilerParameters, codeCompileUnit); compilerResults = csharpCodeProvider.CompileAssemblyFromSource(compilerParameters, sourceCS); if (compilerResults.Errors.Count > 0) { //error line numbers for compileunit are always off from source code Console.WriteLine("Errors building assembly."); foreach (CompilerError error in compilerResults.Errors) { Console.WriteLine(string.Format("\tLine: {0}\r\n\tErrorNumber: {1}\r\n\tErrorText: {2}\r\n", error.Line, error.ErrorNumber, error.ErrorText)); } } else { Console.WriteLine("Success"); } #endregion #region compile VB source //VBCodeProvider vbCodeProvider = null; //Console.WriteLine("Compiling VB:"); //foreach (string sourceLine in sourceVB.Split('\r')) //{ // Console.WriteLine(string.Format("{0}:{1}", ++lineNumber, sourceLine.Replace("\n", ""))); //} //vbCodeProvider = new VBCodeProvider(); //compilerParameters = new CompilerParameters() //{ // GenerateExecutable = false, // GenerateInMemory = true, // IncludeDebugInformation = true //}; //compilerParameters.ReferencedAssemblies.Add("System.dll"); //compilerParameters.ReferencedAssemblies.Add("System.Linq.dll"); ////reference currently executing assembly //compilerParameters.ReferencedAssemblies.Add(System.Reflection.Assembly.GetExecutingAssembly().Location); //compilerResults = null; ////compilerResults = csharCodeProvider.CompileAssemblyFromDom(compilerParameters, codeCompileUnit); //compilerResults = vbCodeProvider.CompileAssemblyFromSource(compilerParameters, sourceVB); //if (compilerResults.Errors.Count > 0) //{ // //error line numbers for compileunit are always off from source code // Console.WriteLine("Errors building assembly."); // foreach (CompilerError error in compilerResults.Errors) // { // Console.WriteLine(string.Format("\tLine: {0}\r\n\tErrorNumber: {1}\r\n\tErrorText: {2}\r\n", error.Line, error.ErrorNumber, error.ErrorText)); // } //} //else //{ // Console.WriteLine("Success"); //} #endregion #region use assembly if (compilerResults.Errors.Count == 0) { Assembly assembly = compilerResults.CompiledAssembly; Type myType = assembly.GetType("MyCodeDOMNamespace.MyType"); Console.WriteLine("Setting MyProperty to a hard coded value of 123."); var myTypeInstance1 = assembly.CreateInstance("MyCodeDOMNamespace.MyType", false, BindingFlags.CreateInstance, null, new string[] { "123" }, null, null); Console.WriteLine("The value of MyProperty is {0}", myType.GetProperty("MyProperty").GetValue(myTypeInstance1)); Console.WriteLine("Setting MyProperty to a referenced value of {0}", myValue); var myTypeInstance2 = assembly.CreateInstance("MyCodeDOMNamespace.MyType", false, BindingFlags.CreateInstance, null, new string[] { myValue }, null, null); Console.WriteLine("The value of MyProperty is {0}", myType.GetProperty("MyProperty").GetValue(myTypeInstance2)); Console.WriteLine("Invoking method to get value from current running assembly"); var myTypeInstance3 = assembly.CreateInstance("MyCodeDOMNamespace.MyType", false, BindingFlags.CreateInstance, null, new string[] { myValue }, null, null); myType.InvokeMember("GetDataFromCurrentlyExecutingAssembly", BindingFlags.InvokeMethod, null, myTypeInstance3, null); /* string CurrentAppDomain = Thread.GetDomain().FriendlyName; AppDomainSetup appDomainSetup = new AppDomainSetup() { ApplicationBase = AppDomain.CurrentDomain.BaseDirectory, DisallowBindingRedirects = false, DisallowCodeDownload = true, ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile }; AppDomain appDomain = AppDomain.CreateDomain("MyAppDomain", null, appDomainSetup); */ } #endregion Console.ReadLine(); }