zoukankan      html  css  js  c++  java
  • Dynamically creating applications using System.CodeDom in VB.NET

    Introduction

    The System.CodeDom namespace in .net allows the users to dynamically compile and create assemblies. This concept is used by ASP.NET internally. The article provides an insight on how to create assemblies dynamically.

    The following are the list of classes, which would be used to create the assembly:

    • CodeNamespace
    • CodeTypeDeclaration
    • CodeCompileUnit
    • CodeEntryPointMethod
    • CodeMemberField
    • CodeMemberProperty
    • CodeMemberMethod
    • CodeParameterDeclarationExpression
    • CodeCompileUnit
    • CompilerParameters
    • CodeSnippetExpression
    • CodeExpressionStatement

    Step 1:

    Add the following namespace declarations,

    Imports
    System
    Imports
    System.CodeDom
    Imports
    System.CodeDom.Compiler
    Imports
    System.IO

    The System.Codedom namespace contains the classes/types necessary to create assemblies at runtime. The above-mentioned classes are contained within this namespace.

    Step 2: Create the following class,

    Public Class
    CCodeGenerator
    Private mynamespace As
    CodeNamespace
    'TODO: INSTANT VB TODO TASK: myclass is a keyword in VB.NET. Change the name or use square brackets to override it:
    Private myclass_Renamed As
    CodeTypeDeclaration
    Private myassembly As
    CodeCompileUnit

    Any code created from Step 3 to Step 10 must reside in the CcodeGenerator class. For clarity and explanation sake, the article has fragmented the code into pieces.

    Step 3:

    The CodeNamespace class is used to add/create namespaces. The name of the namespace can be passed through the constructor of the class.

    Public Sub
    CreateNamespace()
    mynamespace =
    New
    CodeNamespace("mynamespace")
    End
    Sub

    Step 4: Using the mynamespace object, add the list of all namespaces that are used by the assembly.

    Public Sub
    CreateImports()
    mynamespace.Imports.Add(
    New
    CodeNamespaceImport("System"))
    mynamespace.Imports.Add(
    New
    CodeNamespaceImport("System.Drawing"))
    mynamespace.Imports.Add(
    New CodeNamespaceImport("System.Windows.Forms"))

    End
    Sub

    Step 5: Create a class inside the namespace.

    Public Sub
    CreateClass()
    myclass_Renamed =
    New
    CodeTypeDeclaration()
    'Assign a name for the class
    myclass_Renamed.Name = "CMyclass"
    myclass_Renamed.IsClass =
    True
    'Set the Access modifier.
    myclass_Renamed.Attributes = MemberAttributes.Public
    'Add the newly created class to the namespace
    mynamespace.Types.Add(myclass_Renamed)
    End
    Sub

    Step 6: Create a member and add it to the newly created class.

    Public Sub
    CreateMember()
    'Provide the type and variable name
    Dim mymemberfield As CodeMemberField = New CodeMemberField(GetType
    (System.String),"strMessage")
    'Add the member to the class
    myclass_Renamed.Members.Add(mymemberfield)
    End
    Sub

    Step 7: Create a property (with get and set) and add it to the class.

    Public Sub
    CreateProperty()
    Dim mymemberproperty As CodeMemberProperty = New
    CodeMemberProperty()
    'Name of the property
    mymemberproperty.Name = "Message"
    'Data type of the property
    mymemberproperty.Type = New CodeTypeReference(GetType
    (System.String))
    'Access modifier of the property
    mymemberproperty.Attributes = MemberAttributes.Public
    'Add the property to the class
    myclass_Renamed.Members.Add(mymemberproperty)
    'Add the code-snippets to the property.
    'If required, we can also add some custom validation code.
    'using the CodeSnippetExpression class.
    'Provide the return <propertyvalue> statement-For getter
    Dim getsnippet As CodeSnippetExpression = New
    CodeSnippetExpression("return strMessage")
    'Assign the new value to the property-For setter
    Dim setsnippet As CodeSnippetExpression = New
    CodeSnippetExpression("strMessage=value")
    'Add the code snippets into the property
    mymemberproperty.GetStatements.Add(getsnippet)
    mymemberproperty.SetStatements.Add(setsnippet)
    End
    Sub

    Step 8:

    Create a method. Please take utmost care when assigning values to the CodeSnippetExpression class, as any statement provided must be not have any syntax error(s). Since the assembly would be created at runtime (dynamically), the compiler would simply throw all.

    Compile-time error(s) and we don't have any prudent means to find and eliminate the error.

    Public Sub
    CreateMethod()
    'Create an object of the CodeMemberMethod
    Dim mymethod As CodeMemberMethod = New
    CodeMemberMethod()
    'Assign a name for the method.
    mymethod.Name = "AddNumbers"
    'create two parameters
    Dim cpd1 As CodeParameterDeclarationExpression = New CodeParameterDeclarationExpression(GetType(Integer
    ),"a")
    Dim cpd2 As CodeParameterDeclarationExpression = New CodeParameterDeclarationExpression(GetType(Integer
    ),"b")
    'Add the parameters to the method.
    mymethod.Parameters.AddRange(New
    CodeParameterDeclarationExpression() {cpd1, cpd2})
    'Provide the return type for the method.
    Dim ctr As CodeTypeReference = New CodeTypeReference(GetType
    (System.Int32))
    'Assign the return type to the method.
    mymethod.ReturnType = ctr
    'Provide definition to the method (returns the sum of two //numbers)
    Dim snippet1 As CodeSnippetExpression = New
    CodeSnippetExpression("System.Console.WriteLine("" Adding :"" + a + "" And "" + b )")
    'return the value
    Dim snippet2 As CodeSnippetExpression = New
    CodeSnippetExpression("return a+b")
    'Convert the snippets into Expression statements.
    Dim stmt1 As CodeExpressionStatement = New CodeExpressionStatement(snippet1)

    Dim
    stmt2 As CodeExpressionStatement = New CodeExpressionStatement(snippet2)
    'Add the expression statements to the method.
    mymethod.Statements.Add(stmt1)
    mymethod.Statements.Add(stmt2)
    'Provide the access modifier for the method.
    mymethod.Attributes = MemberAttributes.Public
    'Finally add the method to the class.
    myclass_Renamed.Members.Add(mymethod)
    End
    Sub

    Step 9: Create a main method (Entry point for the assembly)

    Public Sub
    CreateEntryPoint()
    'Create an object and assign the name as "Main"
    Dim mymain As CodeEntryPointMethod = New
    CodeEntryPointMethod()
    mymain.Name = "Main"
    'Mark the access modifier for the main method as Public and //static
    mymain.Attributes = MemberAttributes.Public Or
    MemberAttributes.Static
    'Provide defenition to the main method.
    'Create an object of the "Cmyclass" and invoke the method
    'by passing the required parameters.
    Dim exp1 As CodeSnippetExpression = New
    CodeSnippetExpression("CMyclass x = new CMyclass()")
    'Assign value to our property
    Dim exp2 As CodeSnippetExpression = New
    CodeSnippetExpression("x.Message=""Hello World """)
    'Print the value in the property
    Dim exp3 As CodeSnippetExpression = New
    CodeSnippetExpression("Console.WriteLine(x.Message)")
    'Invode the method
    Dim exp4 As CodeSnippetExpression = New
    CodeSnippetExpression("Console.WriteLine(""Answer: {0}"",x.AddNumbers(10,20))")
    Dim exp5 As CodeSnippetExpression = New
    CodeSnippetExpression("Console.ReadLine()")
    'Create expression statements for the snippets
    Dim ces1 As CodeExpressionStatement = New
    CodeExpressionStatement(exp1)
    Dim ces2 As CodeExpressionStatement = New
    CodeExpressionStatement(exp2)
    Dim ces3 As CodeExpressionStatement = New
    CodeExpressionStatement(exp3)
    Dim ces4 As CodeExpressionStatement = New
    CodeExpressionStatement(exp4)
    Dim ces5 As CodeExpressionStatement = New
    CodeExpressionStatement(exp5)
    'Add the expression statements to the main method.
    mymain.Statements.Add(ces1)
    mymain.Statements.Add(ces2)
    mymain.Statements.Add(ces3)
    mymain.Statements.Add(ces4)
    mymain.Statements.Add(ces5)
    'Add the main method to the class
    myclass_Renamed.Members.Add(mymain)
    End
    Sub

    Step 10: Compile the class and create the assembly.

    Public Sub
    SaveAssembly()
    'Create a new object of the global CodeCompileUnit class.
    myassembly = New
    CodeCompileUnit()
    'Add the namespace to the assembly.
    myassembly.Namespaces.Add(mynamespace)
    'Add the following compiler parameters. (The references to the //standard .net dll(s) and framework library).
    Dim comparam As CompilerParameters = New CompilerParameters(New String
    () {"mscorlib.dll"})
    comparam.ReferencedAssemblies.Add("System.dll")comparam.ReferencedAssemblies.Add("System.Drawing.dll")
    comparam.ReferencedAssemblies.Add("System.Windows.Forms.dll")
    'Indicates Whether the compiler has to generate the output in //memory
    comparam.GenerateInMemory =
    False
    'Indicates whether the output is an executable.
    comparam.GenerateExecutable =
    True
    'provide the name of the class which contains the Main Entry //point method
    comparam.MainClass = "mynamespace.CMyclass"
    'provide the path where the generated assembly would be placed
    If Directory.Exists("c:\temp")
    Then
    comparam.OutputAssembly = "c:\temp\HelloWorld.exe"
    Else
    Directory.CreateDirectory("c:\temp")
    comparam.OutputAssembly = "c:\temp\HelloWorld.exe"
    End
    If
    'Create an instance of the c# compiler and pass the assembly to //compile
    Dim ccp As Microsoft.CSharp.CSharpCodeProvider = New
    Microsoft.CSharp.CSharpCodeProvider()
    Dim icc As
    ICodeCompiler = ccp.CreateCompiler()
    'The CompileAssemblyFromDom would either return the list of
    'compile time errors (if any), or would create the
    'assembly in the respective path in case of successful //compilation
    Dim compres As
    CompilerResults = icc.CompileAssemblyFromDom(comparam,myassembly)
    If compres Is Nothing OrElse compres.Errors.Count>0
    Then
    Dim i As Integer
    =0
    Do While
    i<compres.Errors.Count
    Console.WriteLine(compres.Errors(i))
    i += 1
    Loop
    End
    If
    End
    Sub

    Step 11: Create a test component to create the assembly.

    Imports
    System
    amespace
    nmTest
    Friend Class
    DynamicAssemblies
    <STAThread> _
    Shared Sub Main(ByVal args As String
    ())
    Dim cg As CCodeGenerator = New
    CCodeGenerator()
    cg.CreateNamespace()
    cg.CreateImports()
    cg.CreateClass()
    cg.CreateMember()
    cg.CreateProperty()
    cg.CreateMethod()
    cg.CreateEntryPoint()
    cg.SaveAssembly()
    Console.ReadLine()
    End
    Sub
    End
    Class
    End
    Namespace

    The HelloWorld.exe would be created in the mentioned path. The output of the assembly would be as follows:



    Conclusion

    The facility to dynamically create assemblies would be of immense use, when developing real-world applications that demand a great amount of flexibility and scalability.

    NOTE: THIS ARTICLE IS CONVERTED FROM C# TO VB.NET USING A CONVERSION TOOL. ORIGINAL ARTICLE CAN BE FOUND ON C# CORNER (
    WWW.C-SHARPCORNER.COM).

  • 相关阅读:
    二分查找 java代码
    Failed at the bitcore-node@3.1.3 preinstall script './scripts/download' 设置linux proxy (代理)的方式
    github命令行实用操作
    H5无障碍旁白模式使用网页支持
    Vue框架搭建入门到熟悉
    解决IOS下返回不刷新的问题
    小程序—跳转 数据传递
    微信小程序——地图
    常用的正则判断
    JS 控制输入框输入表情emoji 显示在页面上
  • 原文地址:https://www.cnblogs.com/snowball/p/865178.html
Copyright © 2011-2022 走看看