Спасибо всем, кто помог мне с проблемой. Я закончил тем, что создал шаблон T4. Все остальные предложенные варианты были неподходящими по разным причинам.
Для тех, кто находится в такой ситуации, как я, это то, что я сделал:
- Мой класс (имя класса и реализация здесь опущены), в котором реализована вся бизнес-реализация, выглядит примерно так:
Public Class Class1
Public Property Property1 As String
Public Property Property2 As String
Public Property Property3 As Decimal
Public Sub Method1(Of T)(arg1 As T, arg2 As String)
Throw New NotImplementedException
End Sub
Public Sub Method2(Of T)(arg1 As T, arg2 As String)
Throw New NotImplementedException
End Sub
Public Sub Method3(Of T)(arg1 As T, arg2 As String, arg3 As Integer)
Throw New NotImplementedException
End Sub
Public Function Function1(Of T)(arg1 As T, arg2 As String) As String
Throw New NotImplementedException
End Function
Public Function Function2(Of T)(arg1 As T, arg2 As String) As List(Of T)
Throw New NotImplementedException
End Function
Public Function Function3(Of T)(arg1 As T, arg2 As String, arg3 As Integer) As Decimal
Throw New NotImplementedException
End Function
End Class
Я добавил шаблон T4 в проект с именем Class1OfT.tt
и установил его свойства Build Action = None
и Custom Tool = TextTemplatingFileGenerator
Добавлен следующий код в мой Class1OfT.tt
файл:
<#@ template debug="true" hostspecific="true" language="VB" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="Microsoft.VisualBasic" #>
<#@ output extension=".vb" #>
'------------------------------------------------------------------------------
' <auto-generated>
' This code was generated from a template.
'
' Manual changes to this file may cause unexpected behavior in your application.
' Manual changes to this file will be overwritten if the code is regenerated.
' </auto-generated>
'------------------------------------------------------------------------------
<#
Const ClassName = "Class1"
#>
Option Strict On
Option Compare Text
Imports System.Data.SqlClient
Public Class <#= ClassName #>(Of T)
Private ClsObj As <#= ClassName #>
<#
Dim reProperty As New Regex("Public Property (?<name>\w+)(?<sig>(?: As [^=]+))", RegexOptions.Compiled Or RegexOptions.IgnoreCase)
Dim reFunction As New Regex("Public Function (?<name>\w+)(?<of>\(Of [^\)]*\))?(?<sig>\(.*\)(?: As .+)?)", RegexOptions.Compiled Or RegexOptions.IgnoreCase)
Dim reSub As New Regex("Public Sub (?<name>\w+)(?<of>\(Of [^\)]*\))?(?<sig>\(.*\))", RegexOptions.Compiled Or RegexOptions.IgnoreCase)
Dim absolutePath As String = Host.ResolvePath(ClassName & ".vb")
Dim contents As String = IO.File.ReadAllText(absolutePath)
contents = contents.Substring(contents.IndexOf("Public Class " & ClassName))
contents = contents.Substring(0, contents.IndexOf("End Class"))
contents = contents.Replace(vbTab, " ")
For Each line As String In Split(contents, vbNewLine)
line = Trim(line)
If line Like "Public ReadOnly Property *" Then
#>
<#= line #>
<#
ElseIf line Like "Public Property *" Then
Dim groups = reProperty.Match(line).Groups
#>
Public Property <#= groups("name").Value #><#= groups("sig").Value.TrimEnd #>
Get
Return ClsObj.<#= groups("name").Value #>
End Get
Set(value<#= groups("sig").Value.TrimEnd #>)
ClsObj.<#= groups("name").Value #> = value
End Set
End Property
<#
ElseIf line Like "Public Function *" Then
Dim groups = reFunction.Match(line).Groups
#>
Public Function <#= groups("name").Value #><#= groups("sig").Value #>
Return ClsObj.<#= GetFnDef(groups("name").Value, groups("of").Value, groups("sig").Value) #>
End Function
<#
ElseIf line Like "Public Sub *" AndAlso Not line Like "Public Sub New(*" Then
Dim groups = reSub.Match(line).Groups
#>
Public Sub <#= groups("name").Value #><#= groups("sig").Value #>
ClsObj.<#= GetFnDef(groups("name").Value, groups("of").Value, groups("sig").Value) #>
End Sub
<#
End If
Next
#>
End Class
<#+
Function GetFnDef(name As String, ofPart As String, fnArgs As String) As String
Static reArgName As New RegularExpressions.Regex("^\w+$", RegularExpressions.RegexOptions.Compiled)
If fnArgs.StartsWith("(") Then fnArgs = fnArgs.SubString(1)
Dim parts() As String = Split(fnArgs)
Dim args = Enumerable.Range(0, parts.Length).Where(Function(n) parts(n) = "As").Select(Function(n) parts(n - 1)).ToList
For i As Integer = args.Count - 1 To 0 Step -1
If args(i) Like "*()" Then args(i) = args(i).Substring(0, args(i).Length - 2)
If Not reArgName.IsMatch(args(i)) Then args.RemoveAt(i)
Next
If String.IsNullOrEmpty(ofPart) Then
Return String.Concat(name, "(", Join(args.ToArray, ", "), ")")
Else
Return String.Concat(name, "(Of T)(", Join(args.ToArray, ", "), ")")
End If
End Function
#>
- При сохранении файла создается новый файл с именем
Class1OfT.vb
, имеющий следующий код. Именно то, что мне нужно.
'------------------------------------------------------------------------------
' <auto-generated>
' This code was generated from a template.
'
' Manual changes to this file may cause unexpected behavior in your application.
' Manual changes to this file will be overwritten if the code is regenerated.
' </auto-generated>
'------------------------------------------------------------------------------
Option Strict On
Option Compare Text
Imports System.Data.SqlClient
Public Class Class1(Of T)
Private ClsObj As Class1
Public Property Property1 As String
Get
Return ClsObj.Property1
End Get
Set(value As String)
ClsObj.Property1 = value
End Set
End Property
Public Property Property2 As String
Get
Return ClsObj.Property2
End Get
Set(value As String)
ClsObj.Property2 = value
End Set
End Property
Public Property Property3 As Decimal
Get
Return ClsObj.Property3
End Get
Set(value As Decimal)
ClsObj.Property3 = value
End Set
End Property
Public Sub Method1(arg1 As T, arg2 As String)
ClsObj.Method1(Of T)(arg1, arg2)
End Sub
Public Sub Method2(arg1 As T, arg2 As String)
ClsObj.Method2(Of T)(arg1, arg2)
End Sub
Public Sub Method3(arg1 As T, arg2 As String, arg3 As Integer)
ClsObj.Method3(Of T)(arg1, arg2, arg3)
End Sub
Public Function Function1(arg1 As T, arg2 As String) As String
Return ClsObj.Function1(Of T)(arg1, arg2)
End Function
Public Function Function2(arg1 As T, arg2 As String) As List(Of T)
Return ClsObj.Function2(Of T)(arg1, arg2)
End Function
Public Function Function3(arg1 As T, arg2 As String, arg3 As Integer) As Decimal
Return ClsObj.Function3(Of T)(arg1, arg2, arg3)
End Function
End Class