65.9K
CodeProject 正在变化。 阅读更多。
Home

ModelStudio

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.20/5 (4投票s)

2008年12月6日

CPOL

4分钟阅读

viewsIcon

35690

downloadIcon

403

类图和代码生成工具。

Sample screens

引言

在您实际开始编程软件之前,类图在为软件系统开发模型方面非常重要。它们为设计人员、架构师和开发人员提供了一个图形界面,用于操作方法、属性、字段、事件,以及像类、接口、结构等数据结构。在本文中,我们将使用我称之为 ModelStudio 的设计器来帮助您在直接深入代码之前创建模型结构,并且在我们与这个设计器交互时,应注意代码将在后台更新,之后使用 System.CodeDom 命名空间进行自动生成。

背景

我认为首先对代码进行建模是面向对象编程和设计优秀软件应用程序架构的一个良好开端。如果您正在寻找一种反射式解决方案,那么您可能想看看 Sacha Barber 的 100% 反射式类图创建工具。对于本文不讨论的图表工具,我修改并使用了 Barber 工具中的 ClassDrawerContainerPanel 和相关类。我还想承认 Chagosoft 的 cDOMx 类生成器 中的一些想法。

使用 ModelStudio

ModelStudio 应用程序使用 ModelStudio 框架(我们称之为)来创建 Visual Basic 和 C# 代码文档。使用 ModelStudio 非常直接。

  1. 当您启动程序时,您会看到一个空白画布。
  2. 要开始创建您的第一个类,只需单击“新建命名空间”按钮,为其命名,然后就会创建一个新的 Namespace 对象。
  3. 然后,只需从左侧选择命名空间即可添加“新建导入”或“新建类”。
  4. 要向类添加属性和方法,只需选择所需的类并使用“新建属性”或“新建方法”按钮。向方法添加参数也非常简单;只需从左侧选择方法并单击“新建参数”。
  5. 当您对项目满意时,您可以通过以下选项来获取代码:
    1. 使用“生成代码”按钮以您想要的语言检索项目的代码。
    2. 使用“生成文件”按钮以您想要的语言在选定文件夹中生成单独的类文档。
    3. 您还可以选择将项目(存储库)另存为文件,以便将来进行编辑或传输,方法是单击“保存”按钮。
  6. 要打开项目文件,请使用“打开”按钮,浏览到该文件,项目将被加载。

目的

关于我创建此资源工具的初衷,我需要添加一点说明。从 Visual Studio 2005 开始,Microsoft 包含了一个他们称之为 类设计器 的工具。类设计器工具可能适合您的组织,特别是如果您拥有功能强大的 Visual Studio Team System。但是,我不喜欢类设计器工具的“小缺点”。例如,我希望所有生成的类在类构造时初始化任何自定义类型。

Books = New List(of Book)

类设计器却忽略了这一点。其次,难道不希望所有属性都有完整的 setter 和 getter,并且自动声明关联的字段吗?类设计器也忽略了这一点。相反,类设计器默认只提供一个原型化的类属性。

原型
Public Overridable Property Name() As String
    Get

    End Get
    Set(ByVal value As String)

    End Set
End Property
理想
Private m_Name As String

Public Overridable Property Name() As String
    Get
        Return Me.m_Name
    End Get
    Set(ByVal value As String)
        Me.m_Name = value
    End Set
End Property

框架

ModelStudio 框架实现了一个简单的设计,它首先将类信息封装到一个简单的类“外观”中。这里我们 liberal 地使用了“外观”一词。定义“事物的表面外观或假象。(例如:他们设法维持了财富的外观)”。这些外观类及其中的数据随后被“翻译”(我们将在后面讨论),以创建用于代码生成的实际 CodeDom 类。

ModelStudio Framework

外观

CodeDomImport

描述:这是一个示例外观类,将用于为生成的类创建新的 Imports(即 using)语句。

Public Class CodeDomImport
    Implements ICodeMember

    Private m_Import As String = "System.Text"
    Private m_Parent As Object

    ''' Initialize a new instance of the CodeDomImport object
    ''' The fully qualified Namespace that will be imported ie: System.Text
    Sub New(ByVal ImportName As String)
        m_Import = ImportName
    End Sub

    ''' The fully qualified Namespace that represents the import ie: System.text
    Public Property Name() As String Implements ICodeMember.Name
        Get
            Return m_Import
        End Get
        Set(ByVal value As String)
            m_Import = value
        End Set
    End Property

    Public Property Parent() As Object
        Get
            Return m_Parent
        End Get
        Set(ByVal value As Object)
            m_Parent= value
        End Set
    End Property

End Class

CodeGenerator 类

这是整个项目的核心部分。这里是将实际代码翻译、准备并生成到代码文件的位置。

基本上,这个类的结构不是理想的。但是,为了本文的目的,所有内容都包含在这个类中。翻译发生在我们返回一个常规的 CodeDOM CodeNamespace 时。

转换

Public Function GetNamespace(ByVal _Namespace As CodeDomNamespace) As CodeNamespace
    Dim _space As CodeDomNamespace = _Namespace
    Dim _ns As CodeNamespace = _Namespace.DOMNameSpace

    '==Imports
    If _space.Imports.Count > 0 Then
        For Each import As CodeDomImport In _space.Imports
            Dim im As New CodeNamespaceImport(import.Name)
            _ns.Imports.Add(im)
        Next
    End If
....
End Function

准备工作

现在,我们需要按照我们想要的方式准备代码以供输出。在我们称之为准备阶段,您将使用以下 CodeDom 命名空间:

Imports System.CodeDom
Imports System.CodeDom.Compiler

为了准备类在类构造时初始化所有自定义类型,我们使用以下代码:

Dim mcdClass As CodeTypeDeclaration = _Class.DOMClass
'Constructors
For Each meth As CodeDomMethod In _Class.Constructors
    If meth.Parameters.Count > 0 Or _Class.CustomTypes.Count > 0 Then
        Dim cnstr As New CodeDom.CodeConstructor

        For Each param As CodeDomParameter In meth.Parameters
            cnstr.Parameters.Add(New _
                  CodeParameterDeclarationExpression(param.Type, param.Name))
        Next
        
        ' Here is where custom initialization begins
        For Each p As CodeDomProperty In _Class.CustomTypes
            Dim this As New CodeThisReferenceExpression()
            Dim leftExpression As New CodePropertyReferenceExpression(this, p.Name)
            Dim rightExpression As New _
                CodeObjectCreateExpression(New CodeTypeReference(p.Type))

            Dim assign As New CodeAssignStatement(leftExpression, rightExpression)

            cnstr.Statements.Add(assign)
        Next p

        mcdClass.Members.Add(cnstr)
    End If
Next meth

现在,您可以通过简单地调整上述命令以满足您自己的个人偏好来更改构造函数,以初始化您想要的任何类型。

生成

这就是我们实际输出已翻译和准备好的内容的地方。显然,我们将在这里生成 VB 代码,但也有一个类似的 C# 生成方法。

Private Sub GenerateVBFile(ByVal n As CodeNamespace, ByVal OutputDirectory As String)
        m_Unit = New CodeCompileUnit
    m_Unit.Namespaces.Add(n)
    ' Generate the code with the VB code provider.
    Dim provider As Microsoft.VisualBasic.VBCodeProvider = _
        New Microsoft.VisualBasic.VBCodeProvider
    ' Build the output file name.

    For Each c As CodeDom.CodeTypeDeclaration In n.Types
        Dim tempUnit As New CodeCompileUnit
        tempUnit.Namespaces.Add(New CodeDom.CodeNamespace(n.Name))
        tempUnit.Namespaces(0).Types.Add(c)

        ' Build the output file name.
        Dim sourceFile As String = OutputDirectory + _
         Path.DirectorySeparatorChar + c.Name + "." + provider.FileExtension

        ' Create a TextWriter to a StreamWriter to an output file.
        Using tw As New IndentedTextWriter(New StreamWriter(sourceFile, False), "    ")

            ' Generate source code using the code provider.
            provider.GenerateCodeFromCompileUnit(tempUnit, tw, New CodeGeneratorOptions())

            ' Close the output file.
            tw.Close()
        End Using
    Next c

End Sub

非常简单,只需设置私有成员并调用 VBCodeProviderGenerateCodeFromCompileUnit 即可输出一个类,该类应如下所示:

Namespace Classroom
    
Public Class Student

    Private m_Name As String
    Private m_StudentID As Integer
    Private m_MyTeacher As Teacher
    Private m_MyChair As Chair
    Private m_IsSpecial As Boolean
    Private m_Books As List(Of Book)

    Private Sub New()
        MyBase.New
        Me.MyTeacher = New Teacher
        Me.MyChair = New Chair
        Me.Books = New List(Of Book)
    End Sub

    Public Overridable Property Name() As [String]
        Get
            Return Me.m_Name
        End Get
        Set
            Me.m_Name = value
        End Set
    End Property
    ...
End Class
End Namespace

总结

最后一步是我们将所有生成的类导入到我们的项目解决方案中。构建并运行它。恭喜,现在真正的工作开始了。

© . All rights reserved.