我有以下代码
var response = emailValidation();
if(response.Successful) response = emailContentLoad();
if(response.Successful) response = emailPlaceholdersLoad();
// Possibly more calls
if(response.Successful) response = sendEmail();
return response
这四个方法返回一个Response
对象,该对象具有Successful
属性,指示执行期间是否抛出任何异常。
虽然我确实达到了目的,但我想知道是否有更好的方法可以做到这一点?可能是一种模式,但不会损害可读性。
答案 0 :(得分:0)
我现在可以想到两种解决方案。
在代码示例中,您将在几个步骤中改变相同的变量,具体取决于之前的结果。这可以很容易地表示为操作序列(假设所有方法都具有相同的签名)。这样的事情。
// sequence of the methods that will be chained WITHOUT the first method
var operations = new List<Fuc<...>>()
{
method2,
method3,
method4,
};
// returns the first failed operation or the the last operation from the
// operations list
var result =
operations
.Aggregate(
seed: method1(),
func: (seed, op) => seed.Successful ? op() : seed
);
通过这种方式,您可以轻松地在操作列表中添加新操作。
如果你不是LINQ的粉丝那么:
var operations = new List<Func<...>>()
{
method2,
method3,
method4,
};
var response = method1();
foreach(var op in operations)
{
if(response.Successful)
{
response = op();
}
else
{
break;
}
}
您可以查看 Option type (功能语言中流行的概念)
检查此github project以获取c#实施和解释。
This可以给你另一个(lang:F#)
答案 1 :(得分:0)
您也可以写extension methods将这些链接在一起:
Response response = EmailContentLoad().EmailPlaceholdersLoad().SendEmail();
方法看起来像这样:
public static Response EmailContentLoad(this Response response)
{
if(!response.Successful)
{
return response;
}
//Do whatever the method normally does
}
这更具可读性和可扩展性,现在您可以按任何顺序调用方法(如果需要),并且您不必维护链式if语句的单个函数。
我做了一个小提琴here来说明。
答案 2 :(得分:-1)
这不是一种模式,但你可以这样写:
Private Sub CreateWordMergeDoc_Click()
On Error GoTo Err_CreateWordMergeDoc_Click
Dim strSQL, strChurch, strDistLang, strFind, strReplace As String
Dim wrdApp As Word.Application
Dim wrdDoc As Word.Document
Dim wrdMergeDoc As Word.Document
Dim strFilepath As String
strFilepath = "O:\Church Phone List"
'Require choice for church and district
If IsNull(Me![ChurchCombo]) = True Then
MsgBox "Select church", , "Church Phone List"
Me.ChurchCombo.SetFocus
GoTo CloseSub
End If
strChurch = Me![ChurchCombo]
strDistLang = Me![DistrictChoiceCombo]
If strDistLang = "" Then
MsgBox "Select District", , "Church Phone List"
Me.DistrictChoiceCombo.SetFocus
GoTo CloseSub
Else
strDistLang = IIf(Me![DistrictChoiceCombo] = "", "Church", Me![DistrictChoiceCombo])
End If
'Create SQL string from present church/district information
strSQL = "SELECT Churches.* " & vbCrLf & _
"FROM Churches " & vbCrLf & _
"WHERE (((Churches.Church)='" & strChurch & "') AND ((Churches.[District/Language])Like'" & strDistLang & "')) " & vbCrLf & _
"ORDER BY Churches.NAME;"
Set wrdApp = CreateObject("Word.Application")
wrdApp.Visible = True
Set wrdDoc = wrdApp.Documents.Open(strFilepath & "\Phone Merge Document.docx")
With wrdDoc
With .ActiveWindow
'Open the header/footer and add the church (and district if appropriate)
.ActivePane.View.SeekView = WdSeekView.wdSeekCurrentPageHeader
.Selection.EndKey Unit:=wdLine
.Selection.TypeText Text:=strChurch & IIf(strDistLang <> "Church", " (" & strDistLang & ")", "")
'Close header/footer
.ActivePane.View.SeekView = WdSeekView.wdSeekMainDocument
End With
With .MailMerge
.MainDocumentType = wdCatalog
.OpenDataSource NAME:= _
GetNamePath _
, ConfirmConversions:=False, ReadOnly:=False, LinkToSource:=True, _
AddToRecentFiles:=False, PasswordDocument:="", PasswordTemplate:="", _
WritePasswordDocument:="", WritePasswordTemplate:="", Revert:=False, _
Format:=wdOpenFormatAuto, Connection:= _
"DSN=MS Access Database;DBQ=" & strFilepath & "2017\Phone List 2017.mdb;DriverId=25;FIL=MS Access;MaxBufferSize=2048;PageTimeout=5;" _
, SQLStatement:=strSQL, SubType:= _
wdMergeSubTypeOther
.Destination = wdSendToNewDocument
.SuppressBlankLines = True
With .DataSource
.FirstRecord = wdDefaultFirstRecord
.LastRecord = wdDefaultLastRecord
End With
.Execute Pause:=False
End With
.Close SaveChanges:=wdDoNotSaveChanges
End With
With wrdApp
.Selection.WholeStory
With .Selection.ParagraphFormat
.SpaceBeforeAuto = False
.SpaceAfterAuto = False
End With
.Selection.ParagraphFormat.TabStops.ClearAll
.ActiveDocument.DefaultTabStop = InchesToPoints(0.5)
'Add a tab stop
.Selection.ParagraphFormat.TabStops.Add Position:=InchesToPoints(0.1), _
Alignment:=wdAlignTabLeft, Leader:=wdTabLeaderSpaces
'Replace (C) and (¢) with [C] and [c] since auto replace for (c) may be enabled
.Selection.Find.Replacement.ClearFormatting
With .Selection.Find
.Text = "(C)"
.Replacement.Text = "[C]"
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
.Selection.Find.Execute Replace:=wdReplaceAll
With .Selection.Find
.Text = "(¢)"
.Replacement.Text = "[c]"
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
.Selection.Find.Execute Replace:=wdReplaceAll
'Lock document so track changes stays on
.ActiveDocument.Protect Password:="onebody1", NoReset:=False, Type:= _
wdAllowOnlyRevisions, UseIRM:=False, EnforceStyleLock:=False
.ChangeFileOpenDirectory _
strFilepath & "\Track-Change Documents\"
End With
strFind = "/"
strReplace = " "
strDistLang = Replace(strDistLang, strFind, strReplace)
wrdApp.ActiveDocument.SaveAs2 FileName:=strChurch & IIf(strDistLang <> "Church", " - " & strDistLang, ""), FileFormat _
:=wdFormatXMLDocument, LockComments:=False, Password:="", _
AddToRecentFiles:=True, WritePassword:="", ReadOnlyRecommended:=False, _
EmbedTrueTypeFonts:=False, SaveNativePictureFormat:=False, SaveFormsData _
:=False, SaveAsAOCELetter:=False, CompatibilityMode:=14
wrdApp.ActiveDocument.Activate
'quit the word application:
wrdApp.Quit
MsgBox "Completed", , "Church Phone List"
CloseSub:
'Clear the object variables:
Set wrdDoc = Nothing
Set wrdApp = Nothing
Exit_CreateWordMergeDoc_Click:
Set wrdDoc = Nothing
Set wrdApp = Nothing
Exit Sub
Err_CreateWordMergeDoc_Click:
MsgBox Err.Description
Resume Exit_CreateWordMergeDoc_Click
End Sub
你仍然拥有相同数量的if语句,但是一旦发生错误,函数就会终止,并且将避免不必要的检查。
作为建议,我不会捕获这些方法中的所有异常。相反,我会抓住他们想要处理它或你想向用户显示错误消息的位置。因此,您可以将代码简化为:
var response = emailValidation();
if(!response.Successful) return response;
response = emailContentLoad();
if(!response.Successful) return response;
response = emailPlaceholdersLoad();
if(!response.Successful) return response;
response = sendEmail();
return response