类似Visual Studio的代码生成:在运行时生成基本类实现代码

时间:2016-01-25 11:46:06

标签: reflection code-generation codedom

我有一个允许用户编写插件的项目。我包含一个允许在C#和VB.NET中编写代码并使用CodeDom编译器编译它的小型IDE。每个插件都继承了一个特定的基类。

为了让用户的生活更轻松,我提供了各种插件类型的基本模板。基本上当用户创建一个XY类型的新插件时,他从一个类似于你写的时候的基本实现开始

Public Class Foo
    Inherits BaseFoo

并在Visual Studio中按Enter键。 不酷的是,我刚刚将一些包含预制代码的文本文件添加到资源中并从那里显示它。这种方法很有效,直到对基类的定义进行更改,因为需要相应地调整预制代码。

在框架中,存在从CodeDomProvider派生的类,如Microsoft.VisualBasic.VBCodeGenerator,它们似乎包含基于类型定义创建代码的必要方法。但是,CodeDom方法似乎旨在从头开始创建新类型,例如用于编写脚本,并且在某种意义上与Reflection无法很好地交互,我无法提供MethodInfos等等直接到CodeDom。

我可能会在一起手动构建要生成的类型,例如

Dim v As New Microsoft.VisualBasic.VBCodeProvider
Dim t As New CodeDom.CodeTypeDeclaration("Foo")
t.Attributes = CodeDom.MemberAttributes.Public
Dim r As New CodeDom.CodeTypeReference(GetType(Foo))
t.BaseTypes.Add(r)
t.IsClass = True
t.Name = "TestClass"
Dim base = GetType(Foo)

For Each method In base.GetMethods
    If (method.Attributes And Reflection.MethodAttributes.Abstract) > 0 Then
        Dim m As New CodeDom.CodeMemberMethod()
        For Each p In method.GetParameters
            Dim newp As New CodeDom.CodeParameterDeclarationExpression(p.ParameterType, p.Name)
            newp.Direction = If(p.IsIn, CodeDom.FieldDirection.In, CodeDom.FieldDirection.Out)
            m.Parameters.Add(newp)
        Next
        m.Name = method.Name
        m.Attributes = CodeDom.MemberAttributes.Public Or CodeDom.MemberAttributes.Override
        t.Members.Add(m)
    End If
Next

Dim w As New IO.StringWriter
Dim opts As New CodeDom.Compiler.CodeGeneratorOptions
v.GenerateCodeFromType(t, w, opts)

对于示例类

Public MustInherit Class Foo
    Public Property Foo1 As Double
    Public Function What() As Double
        Return Double.NaN
    End Function
    Public MustOverride Sub Test(ByRef Was As Double)
    Public MustOverride ReadOnly Property Something As Double
End Class

这会创建输出

Public Class TestClass
    Inherits TypeGenerator.Foo

    Public Overrides Sub Test(ByRef Was As System.Double&)
    End Sub

    Public Overrides Sub get_Something()
    End Sub
End Class

这是正确的方向,但它似乎很容易出错和非常繁琐。 (在旁注中,为什么它将参数实现为System.Double&甚至不编译?作为ByVal参数,它可以工作。)

有没有更简单的方法来实现我的需求?

  • 有基类
  • 在运行时从其中的定义创建代码模板

0 个答案:

没有答案