Пример #1
0
        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
            };
        }
Пример #2
0
 /// <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);
     }
 }
Пример #3
0
        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();
        }