我在使用SmallTalk时收到邮件的发件人时遇到问题。我想要完成的是从另一个方法(B)修改方法(A)的返回值,该方法由第一个方法(A)调用。再次...... A调用B,我希望B从A的上下文中返回一个值。
示例代码:
这将是A:
A
| aResult aPartialResult |
aPartialResult := self B.
"do things with aPartialResult"
^aResult.
这将是B:
B
| aResult |
[ aResult := "do something" ]
on: Exception
do: ["make A return something"].
^aResult.
问题是我想要在B中提出的异常也可以在B中处理。这就是为什么我不只是在B中引发一个例外来处理它并从那里轻松返回。
我以为我可以使用thisContext执行此操作,但发件人为零。对于为什么这样做也得到答案也不会有害......
提前致谢!
答案 0 :(得分:3)
Guillermo,异常处理可以在这里无缝地替换一些不好的想法:
另外,retrieveCart:onErrorReturnFrom:做得太多了。使用所有错误处理程序,实际逻辑会丢失。
所以,我要做的第一件事是创建Error子类来表示你的域概念,例如AddBookError,CartExpiredError,InvalidCartError
然后你只需设置错误信息,可能是:
CartExpiredError>>initialize
super initialize.
self messageText: '1|', UserInterface cartHasExpiredErrorMessage.
接下来的事情(实际上是两个步骤)是用私有访问器替换原始字典方法,私有访问器可以使用新的错误类,如下所示:
timestampFor: aCartId
^ cartCreationDateAndTime at: aCartId ifAbsent: [ InvalidCartError signal ].
和
cartNumber: aCartId
^ carts at: aCartId ifAbsent: [ InvalidCartError signal ].
Cart>>add: aQuantity booksWithISBN: aBookISBN
fail ifTrue: [ AddBookError signal ].
现在,retrieveCart:onErrorReturnFrom:可以变为:
retrieveCart: aCartId
| aCartCreationDateAndTime |
aCartCreationDateAndTime := self timestampFor: aCartId.
Time now > (aCartCreationDateAndTime + 30 minutes) ifTrue: [ CartExpiredError signal ].
^ self cartNumber: aCartId.
最后,大大简化的A变为:
add: aQuantity booksWithISBN: aBookISBN toCart: aCartId
| aCart |
[aCart := self retrieveCart: aCartId.
aCart add: aQuantity booksWithISBN: aBookISBN]
on: Error
do: [ :e | ^ e messageText ].
^ '0|OK'.
这仍然可以被清理(例如,为preTending'1 |'添加到messageText的所有Error类的超类),显然你必须将这个简化版本用于你的实际项目,但是你能开始看到吗?例外如何让你的生活更轻松?
Here是代码的工作模型,在github上传递测试
n.b。我注意到的另一件事是aCartCreationDateAndTime。将它作为购物车的属性似乎更自然,但也许这在实际应用中没有意义......
答案 1 :(得分:1)
一种简单的方法是A将一个带有返回的块传递给B,如:
A
| aResult aPartialResult |
aPartialResult := self BonSpecialConditionDo: [:partial | ^partial].
...snip...
然后
BonSpecialConditionDo: aBlock
| partialResult |
partialResult := self doSomethingPartial.
^[self doSomething]
on: SomeException
do: [:exc | aBlock value: partialResult]
注意,捕捉异常被认为是危险的(你捕获太多东西)。
编辑:我刚刚在处理程序
中删除了一个不必要的返回^编辑:与超级大国一起做(但不要用锤子杀死苍蝇)
B
| partialResult |
partialResult := self doSomethingPartial.
^[self doSomething]
on: SomeException
do: [:exc | thisContext home sender home return: partialResult ]
我以为你可以通过Exception exc访问thisContext(这是实例变量handlerContext),但似乎没有任何方便的消息来访问这个内部状态......
答案 2 :(得分:0)
知道了!
这是A:
A
| aResult aPartialResult |
aPartialResult := self BOnErrorReturnFrom: thisContext.
"do things with aPartialResult"
^aResult.
这将是B:
BOnErrorReturnFrom: aContext
| aResult |
[ aResult := "do something" ]
on: Exception
do: [aContext return: "whatever you want :)"].
^aResult.
在我意识到关键字" thisContext",当在BlockClosure中使用时,并没有返回声明了块的ContextPart但是其他东西之后,这并不是很难(但仍然不确定它是什么。
回应肖恩:
我试图做的是避免重复代码。实现A和B的对象是REST接口的内部(模型侧)部分,所以我希望它返回一个字符串而只返回一个字符串(我不想要异常,也不想要任何不同于字符串对象的东西)通过)。在我的具体问题中,A(很抱歉打破了Smalltalk消息命名约定,但我认为现在更改它会导致进一步的混淆......)会收到购物车ID并会对该购物车执行某些操作。 A必须使用该ID检索购物车,在购物车上进行一些验证,如果有错误,则返回ad hoc消息(始终作为字符串)。将在每个必须检索购物车的消息中重复此检索和验证代码。
这是我最终获得的正确代码:
这是A :(不要注意#try消息。它只是确保没有异常会被转换为字符串。如果有人知道如何以更好的方式做到这一点,请告诉我如何!)
add: aQuantity booksWithISBN: aBookISBN toCart: aCartId
| aCart aContext |
aContext := thisContext.
^self try: [
aCart := self retrieveCart: aCartId onErrorReturnFrom: aContext.
[aCart add: aQuantity booksWithISBN: aBookISBN]
on: Error
do: [ :anError | ^'1|', (self formatAsResponse: anError messageText) ].
^'0|OK'.
].
这是B:
retrieveCart: aCartId onErrorReturnFrom: aContext
| aCartCreationDateAndTime aCart |
[aCartCreationDateAndTime := cartCreationDateAndTime at: aCartId asInteger.]
on: KeyNotFound
do: [ aContext return: ('1|', (UserInterface invalidCartIdErrorMessage)).].
(systemClock now > (aCartCreationDateAndTime + 30 minutes))
ifTrue: [aContext return: ('1|', (UserInterface cartHasExpiredErrorMessage))].
[aCart := carts at: aCartId asInteger.]
on: KeyNotFound
do: [ aContext return: ('1|', (UserInterface invalidCartIdErrorMessage))].
^aCart.
答案 3 :(得分:0)
A
| aResult aPartialResult |
aPartialResult:= self B。
“用aPartialResult做事”
^ aResult。
乙
| aResult |
[aResult:=“做点什么”] on:例外 做:[“让A返回一些东西”]。 ^ aResult。
我会把它写成
A
| aResult aPartialResult |
aPartialResult:= self B. aPartialResult ifNotNil:[
“用aPartialResult做事”。
^ aResult。
乙
| aResult |
[aResult:=“做点什么”] on:例外 做:[:e | ^ nil]。 ^ aResult。
那么那就是我!!!