处理大量可选参数
Handling Lots of Optional Parameters
我不好意思分享这个功能,但我需要帮助来整理它。很久以前为了一个非常简单的使用而写了这个,但是它已经失控了,我不知道如何正确处理它。
Public Shared Function SetVariables(msg As String, Optional name As String = "", Optional target As String = "", Optional amount As Decimal = 0, Optional cost As String = "0", Optional keyword As String = "", Optional time As String = "", Optional reward As String = "", Optional participantList As String = "", Optional participantCount As Integer = 0, Optional game As String = "", Optional viewers As String = "", Optional followers As String = "", Optional link As String = "", Optional _options As String = "", Optional Year As String = "", Optional Month As String = "", Optional Day As String = "", Optional Hour As String = "", Optional Minute As String = "", Optional grpname As String = "")
Dim balance As Decimal
Dim holdings As Decimal
If name > "" Then
If Options.Accounts.ContainsKey(name) Then
If Options.Holdings.ContainsKey(Options.Accounts.Item(name)) Then
holdings = Options.Holdings.Item(Options.Accounts.Item(name))
End If
balance = Options.Accounts.Item(name).Points
End If
End If
msg = msg.Replace("[name]", StrConv(name, VbStrConv.ProperCase))
If holdings > 0 Then
msg = msg.Replace("[balance]", balance & "[" & holdings & "]")
Else
msg = msg.Replace("[balance]", balance)
End If
msg = msg.Replace("[channel]", Subs.UppercaseFirstLetter(Options.Channel.TrimStart("#")))
msg = msg.Replace("[target]", Subs.UppercaseFirstLetter(target))
msg = msg.Replace("[amount]", amount)
msg = msg.Replace("[cost]", cost)
msg = msg.Replace("[keyword]", keyword)
msg = msg.Replace("[time]", time)
msg = msg.Replace("[reward]", reward)
msg = msg.Replace("[participantList]", participantList)
msg = msg.Replace("[participantCount]", participantCount)
msg = msg.Replace("[botname]", Subs.UppercaseFirstLetter(Options.User))
If msg.Contains("[groups]") Then msg = msg.Replace("[groups]", GetSortedGroups(name))
If msg.Contains("[group]") Then msg = msg.Replace("[group]", GetSortedGroups(name, True))
msg = msg.Replace("[game]", StrConv(game, VbStrConv.ProperCase))
msg = msg.Replace("[viewers]", viewers)
msg = msg.Replace("[followers]", followers)
msg = msg.Replace("[link]", link)
msg = msg.Replace("[options]", options.ToUpper)
msg = msg.Replace("[years]", Year)
msg = msg.Replace("[months]", Month)
msg = msg.Replace("[days]", Day)
msg = msg.Replace("[hours]", Hour)
msg = msg.Replace("[minutes]", Minute)
msg = msg.Replace("[grpname]", StrConv(grpname, VbStrConv.ProperCase))
If balance = 1 Or amount = 1 Then
msg = msg.Replace("[currency]", Options.PName)
Else
msg = msg.Replace("[currency]", Options.PNames)
End If
Return msg
End Function
基本上我向这个函数传递了一个字符串,它包含其中的一些:[name] [keyword] 等,将被替换为其他内容。有时我还必须传递数据以替换那些数据,这就是问题开始的地方。我希望它们在同一个函数中,但我现在可以使用许多参数。我从来没有在函数的一次调用中使用所有这些参数,随着时间的推移,我将添加更多参数。
关于如何更好地处理此类事情的任何建议?我是否应该将此功能拆开并单独处理替换?
您这样做的方式非常昂贵。 Strings
是不可变的,所以像这样的一行:
msg = msg.Replace("[followers]", followers)
...撕开原来的 msg
然后用碎片和替换物创建一个新的。我已经用用户创建的短字符串来指定文本块的布局,但 StringBuilder
对较长的字符串 and/or 进行大量替换会更快、更高效。 This post is an extreme example 使用 1MB 的字符串(SB 将时间从 5 分钟缩短到 86 毫秒)。
因为听起来您构建的起始字符串被切碎了,所以如果可能的话,我会尝试从头开始构建它并一路格式化。我对数据或其他一些方法了解不够,但这应该给你一个想法:
Public Class MessageMaker
Public Property Name As String
Public Property Target As String
Public Property Amount As Nullable(Of Decimal)
Public Property Cost As String ' string? Really?
' illustration
Public Property Participants As List(Of String)
' ergo participantCount==Participants.COunt()
Public Property GroupName As String
' etc ad nauseum
Public Sub New()
Participants = New List(Of String)
End Sub
Public Function GetFormattedMsg() As String
Dim sb As New StringBuilder
sb.AppendFormat("The Name: {0}; ", Name)
' or...this will only append the name when lengh>0
'sb.AppendFormat(If(String.IsNullOrEmpty(Name), "", TitleCase(Name) & "; "))
If Amount.HasValue Then
sb.AppendFormat("amt = {0}; ", Amount.Value.ToString("C2"))
End If
Dim p As String = ""
If Participants.Count > 0 Then
sb.AppendFormat("Participant Count: {0}; ", Participants.Count)
' convert names to TitleCase, sort
p = String.Join(", ", Participants.OrderBy(Function(x) x).
Select(Function(j) TitleCase(j)))
sb.AppendFormat("Participant Names: {0}; ", p)
End If
sb.Append(If(String.IsNullOrEmpty(GroupName), "",
String.Format("Grp: {0}; ", TitleCase(GroupName))))
Return sb.ToString
End Function
Private Function TitleCase(str As String) As String
Return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower)
End Function
End Class
注意 Amount
是 Nullable(Of Decimal)
(或者可以写成 As Decimal?
)。如果你想省略它,除非它被给出,你可以使用 .HasValue
来确定它。这可以防止误导数字:Amount: 0
真的意味着 0 还是意味着它没有指定。除非那很重要,否则不要理会 Nullable<T>
。
GroupName
处理展示了如何有条件地添加文本。我还将老式的 StrConv
替换为 NET 方法。我不知道 GetSortedGroups
的作用,但如果您愿意,可以即时对任何组列表进行排序(如 Participants
所示)。
根据这个 class 还需要做什么,而不是方法,结果可能来自 .ToString()
:
Public Overrides Function ToString() As String
' all the code
Return msg
End Function
测试代码:
Dim mm As New MessageMaker
mm.Name = "April Gala Festival"
mm.Amount = 1.23D
mm.Participants = New List(Of String) From {"ziggy", "zOEy", "HOOveR", "josh"}
Dim msg = mm.GetFormattedMsg()
' or
Dim msg = mm.ToString()
结果:
"The Name: April Gala Festival; amt = .23; Participant Count: 4; Participant Names: Hoover, Josh, Ziggy, Zoey; "
我猜生成的字符串有一些标题和分隔符。该方法在每个段或元素后使用 "; "
。
我不好意思分享这个功能,但我需要帮助来整理它。很久以前为了一个非常简单的使用而写了这个,但是它已经失控了,我不知道如何正确处理它。
Public Shared Function SetVariables(msg As String, Optional name As String = "", Optional target As String = "", Optional amount As Decimal = 0, Optional cost As String = "0", Optional keyword As String = "", Optional time As String = "", Optional reward As String = "", Optional participantList As String = "", Optional participantCount As Integer = 0, Optional game As String = "", Optional viewers As String = "", Optional followers As String = "", Optional link As String = "", Optional _options As String = "", Optional Year As String = "", Optional Month As String = "", Optional Day As String = "", Optional Hour As String = "", Optional Minute As String = "", Optional grpname As String = "")
Dim balance As Decimal
Dim holdings As Decimal
If name > "" Then
If Options.Accounts.ContainsKey(name) Then
If Options.Holdings.ContainsKey(Options.Accounts.Item(name)) Then
holdings = Options.Holdings.Item(Options.Accounts.Item(name))
End If
balance = Options.Accounts.Item(name).Points
End If
End If
msg = msg.Replace("[name]", StrConv(name, VbStrConv.ProperCase))
If holdings > 0 Then
msg = msg.Replace("[balance]", balance & "[" & holdings & "]")
Else
msg = msg.Replace("[balance]", balance)
End If
msg = msg.Replace("[channel]", Subs.UppercaseFirstLetter(Options.Channel.TrimStart("#")))
msg = msg.Replace("[target]", Subs.UppercaseFirstLetter(target))
msg = msg.Replace("[amount]", amount)
msg = msg.Replace("[cost]", cost)
msg = msg.Replace("[keyword]", keyword)
msg = msg.Replace("[time]", time)
msg = msg.Replace("[reward]", reward)
msg = msg.Replace("[participantList]", participantList)
msg = msg.Replace("[participantCount]", participantCount)
msg = msg.Replace("[botname]", Subs.UppercaseFirstLetter(Options.User))
If msg.Contains("[groups]") Then msg = msg.Replace("[groups]", GetSortedGroups(name))
If msg.Contains("[group]") Then msg = msg.Replace("[group]", GetSortedGroups(name, True))
msg = msg.Replace("[game]", StrConv(game, VbStrConv.ProperCase))
msg = msg.Replace("[viewers]", viewers)
msg = msg.Replace("[followers]", followers)
msg = msg.Replace("[link]", link)
msg = msg.Replace("[options]", options.ToUpper)
msg = msg.Replace("[years]", Year)
msg = msg.Replace("[months]", Month)
msg = msg.Replace("[days]", Day)
msg = msg.Replace("[hours]", Hour)
msg = msg.Replace("[minutes]", Minute)
msg = msg.Replace("[grpname]", StrConv(grpname, VbStrConv.ProperCase))
If balance = 1 Or amount = 1 Then
msg = msg.Replace("[currency]", Options.PName)
Else
msg = msg.Replace("[currency]", Options.PNames)
End If
Return msg
End Function
基本上我向这个函数传递了一个字符串,它包含其中的一些:[name] [keyword] 等,将被替换为其他内容。有时我还必须传递数据以替换那些数据,这就是问题开始的地方。我希望它们在同一个函数中,但我现在可以使用许多参数。我从来没有在函数的一次调用中使用所有这些参数,随着时间的推移,我将添加更多参数。
关于如何更好地处理此类事情的任何建议?我是否应该将此功能拆开并单独处理替换?
您这样做的方式非常昂贵。 Strings
是不可变的,所以像这样的一行:
msg = msg.Replace("[followers]", followers)
...撕开原来的 msg
然后用碎片和替换物创建一个新的。我已经用用户创建的短字符串来指定文本块的布局,但 StringBuilder
对较长的字符串 and/or 进行大量替换会更快、更高效。 This post is an extreme example 使用 1MB 的字符串(SB 将时间从 5 分钟缩短到 86 毫秒)。
因为听起来您构建的起始字符串被切碎了,所以如果可能的话,我会尝试从头开始构建它并一路格式化。我对数据或其他一些方法了解不够,但这应该给你一个想法:
Public Class MessageMaker
Public Property Name As String
Public Property Target As String
Public Property Amount As Nullable(Of Decimal)
Public Property Cost As String ' string? Really?
' illustration
Public Property Participants As List(Of String)
' ergo participantCount==Participants.COunt()
Public Property GroupName As String
' etc ad nauseum
Public Sub New()
Participants = New List(Of String)
End Sub
Public Function GetFormattedMsg() As String
Dim sb As New StringBuilder
sb.AppendFormat("The Name: {0}; ", Name)
' or...this will only append the name when lengh>0
'sb.AppendFormat(If(String.IsNullOrEmpty(Name), "", TitleCase(Name) & "; "))
If Amount.HasValue Then
sb.AppendFormat("amt = {0}; ", Amount.Value.ToString("C2"))
End If
Dim p As String = ""
If Participants.Count > 0 Then
sb.AppendFormat("Participant Count: {0}; ", Participants.Count)
' convert names to TitleCase, sort
p = String.Join(", ", Participants.OrderBy(Function(x) x).
Select(Function(j) TitleCase(j)))
sb.AppendFormat("Participant Names: {0}; ", p)
End If
sb.Append(If(String.IsNullOrEmpty(GroupName), "",
String.Format("Grp: {0}; ", TitleCase(GroupName))))
Return sb.ToString
End Function
Private Function TitleCase(str As String) As String
Return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower)
End Function
End Class
注意 Amount
是 Nullable(Of Decimal)
(或者可以写成 As Decimal?
)。如果你想省略它,除非它被给出,你可以使用 .HasValue
来确定它。这可以防止误导数字:Amount: 0
真的意味着 0 还是意味着它没有指定。除非那很重要,否则不要理会 Nullable<T>
。
GroupName
处理展示了如何有条件地添加文本。我还将老式的 StrConv
替换为 NET 方法。我不知道 GetSortedGroups
的作用,但如果您愿意,可以即时对任何组列表进行排序(如 Participants
所示)。
根据这个 class 还需要做什么,而不是方法,结果可能来自 .ToString()
:
Public Overrides Function ToString() As String
' all the code
Return msg
End Function
测试代码:
Dim mm As New MessageMaker
mm.Name = "April Gala Festival"
mm.Amount = 1.23D
mm.Participants = New List(Of String) From {"ziggy", "zOEy", "HOOveR", "josh"}
Dim msg = mm.GetFormattedMsg()
' or
Dim msg = mm.ToString()
结果:
"The Name: April Gala Festival; amt = .23; Participant Count: 4; Participant Names: Hoover, Josh, Ziggy, Zoey; "
我猜生成的字符串有一些标题和分隔符。该方法在每个段或元素后使用 "; "
。