I have several similar methods, say eg. CalculatePoint(...) and CalculateListOfPoints(...). Occasionally, they may not succeed, and need to indicate this to the caller. For CalculateListOfPoints, which returns a generic List, I could return an empty list and require the caller to check this; however Point is a value type and so I can't return null there.
我有几种类似的方法,例如。 CalculatePoint(...)和CalculateListOfPoints(...)。有时候,它们可能不会成功,需要向呼叫者表明这一点。对于返回通用List的CalculateListOfPoints,我可以返回一个空列表并要求调用者检查这个;但是Point是一个值类型,所以我不能在那里返回null。
Ideally I would like the methods to 'look' similar; one solution could be to define them as
理想情况下,我希望这些方法“看起来”相似;一种解决方案可能是将它们定义为
public Point CalculatePoint(... out Boolean boSuccess);
public List<Point> CalculateListOfPoints(... out Boolean boSuccess);
or alternatively to return a Point? for CalculatePoint, and return null to indicate failure. That would mean having to cast back to the non-nullable type though, which seems excessive.
或者返回一个点?对于CalculatePoint,并返回null以指示失败。这意味着必须回归到非可空类型,这似乎是过度的。
Another route would be to return the Boolean boSuccess, have the result (Point or List) as an 'out' parameter, and call them TryToCalculatePoint or something...
另一种方法是返回布尔boSuccess,将结果(Point或List)作为'out'参数,并将它们称为TryToCalculatePoint或其他...
What is best practice?
什么是最佳做法?
Edit: I do not want to use Exceptions for flow control! Failure is sometimes expected.
编辑:我不想使用Exceptions进行流量控制!有时候会失败。
16 个解决方案
#1
24
Personally, I think I'd use the same idea as TryParse() : using an out parameter to output the real value, and returning a boolean indicating whether the call was successful or not
就个人而言,我认为我使用与TryParse()相同的想法:使用out参数输出实际值,并返回一个布尔值,指示调用是否成功
public bool CalculatePoint(... out Point result);
public bool CalculatePoint(... out point result);
I am not a fan of using exception for "normal" behaviors (if you expect the function not to work for some entries).
我不喜欢为“正常”行为使用异常(如果您希望该函数不适用于某些条目)。
#2
7
Why would they fail? If it's because of something the caller has done (i.e. the arguments provided) then throwing ArgumentException is entirely appropriate. A Try[...] method which avoids the exception is fine.
他们为什么会失败?如果是因为调用者所做的事情(即提供的参数),那么抛出ArgumentException是完全合适的。一个避免异常的Try [...]方法很好。
I think it's a good idea to provide the version which throws an exception though, so that callers who expect that they will always provide good data will receive a suitably strong message (i.e. an exception) if they're ever wrong.
我认为提供引发异常的版本是一个好主意,因此,如果他们错了,那么期望他们将始终提供良好数据的呼叫者将收到适当强烈的消息(即异常)。
#3
5
Another alternative is to throw an exception. However, you generally only want to throw exceptions in "exceptional cases".
另一种方法是抛出异常。但是,您通常只想在“例外情况”中抛出异常。
If the failure cases are common (and not exceptional), then you've already listed out your two options. EDIT: There may be a convention in your project as how to handle such non-exceptional cases (whether one should return success or the object). If there is no existing convention, then I agree with lucasbfr and suggest you return success (which agrees with how TryParse(...) is designed).
如果失败案例很常见(并非例外),那么您已经列出了两个选项。编辑:您的项目中可能有一个约定如何处理此类非特殊情况(无论是应该返回成功还是对象)。如果没有现有的约定,那么我同意lucasbfr并建议你返回成功(这与TryParse(...)的设计方式一致)。
#4
2
If the failure is for a specific reason then I think its ok to return null, or bool and have an out parameter. If however you return null regardless of the failure then I don't recommend it. Exceptions provide a rich set of information including the reason WHY something failed, if all you get back is a null then how do you know if its because the data is wrong, you've ran out of memory or some other weird behavior.
如果失败是出于特定原因,那么我认为可以返回null,或者bool并且有一个out参数。但是,如果无论失败都返回null,那么我不推荐它。异常提供了丰富的信息,包括为什么出现故障的原因,如果你回来的都是null,那么你怎么知道它是否因为数据错误,你的内存不足或其他一些奇怪的行为。
Even in .net the TryParse has a Parse brother so that you can get the exception if you want to.
即使在.net中,TryParse也有一个Parse兄弟,所以如果你愿意,你可以获得异常。
If I provided a TrySomething method I would also provide a Something method that threw an exception in the event of failure. Then it's up to the caller.
如果我提供了TrySomething方法,我还会提供一个Something方法,在发生故障时抛出异常。然后由呼叫者决定。
#5
1
The model I've used is the same one MS uses with the TryParse methods of various classes.
我使用的模型与MS使用的模型与各种类的TryParse方法相同。
Your original code:
public Point CalculatePoint(... out Boolean boSuccess);
public List CalculateListOfPoints(... out Boolean boSuccess);
你原来的代码:public Point CalculatePoint(... out Boolean boSuccess); public List CalculateListOfPoints(... out Boolean boSuccess);
Would turn into public bool CalculatePoint(... out (or ref) Point CalculatedValue);
public bool CalculateListOfPoints(... out (or ref) List CalculatedValues);
会变成公共bool CalculatePoint(... out(或ref)Point CalculatedValue); public bool CalculateListOfPoints(... out(或ref)List CalculatedValues);
Basically you make the success/failure the return value.
基本上,您将成功/失败作为返回值。
#6
1
To summarise there are a couple of approaches you can take:
总结一下,您可以采取以下几种方法:
- When the return type is a value-type, like Point, use the Nullable feature of C# and return a Point? (aka Nullable), that way you can still return null on a failure
- Throw an exception when there's a failure. The whole argument/discussion regarding what is and isn't "exceptional" is a moot point, it's your API, you decide what's exceptional behaviour.
- Adopt a model similar to that implemented by Microsoft in the base types like Int32, provide a CalculatePoint and TryCalculatePoint (int32.Parse and int32.TryParse) and have one throw and one return a bool.
- Return a generic struct from your methods that has two properties, bool Success and GenericType Value.
当返回类型是一个值类型,如Point时,使用C#的Nullable特性并返回一个Point? (又名Nullable),这样你就可以在失败时返回null
发生故障时抛出异常。关于什么是“特殊”和不是“特殊”的整个论点/讨论是一个有争议的问题,它是你的API,你决定什么是特殊行为。
采用类似于Microsoft在Int32等基类型中实现的模型,提供一个CalculatePoint和TryCalculatePoint(int32.Parse和int32.TryParse)并且有一个throw和一个返回bool。
从具有两个属性bool Success和GenericType Value的方法返回一个通用结构。
Dependent on the scenario I tend to use a combination of returning null or throwing an exception as they seem "cleanest" to me and fit best with the existing codebase at the company I work for. So my personal best practice would be approaches 1 and 2.
根据场景我倾向于使用返回null或抛出异常的组合,因为它们对我来说似乎“最干净”并且最适合我工作的公司的现有代码库。所以我个人的最佳实践是方法1和方法2。
#7
1
It mostly depends on the behavior of your methods and their usage.
它主要取决于您的方法的行为及其用法。
If failure is common and non-critical, then have your methods return a boolean indicating their success and use an out parameter to convey the result. Looking up a key in a hash, attempting to read data on a non-blocking socket when no data is available, all these examples fall in that category.
如果失败是常见且非关键的,那么让您的方法返回一个指示其成功的布尔值,并使用out参数来传达结果。查找哈希中的密钥,在没有数据可用时尝试读取非阻塞套接字上的数据,所有这些示例都属于该类别。
If failure is unexpected, return directly the result and convey errors with exceptions. Opening a file read-only, connecting to a TCP server, are good candidates.
如果失败是意外的,则直接返回结果并传达异常错误。以只读方式打开文件,连接到TCP服务器,是很好的选择。
And sometimes both ways make sense...
有时两种方式都有意义......
#8
1
Return Point.Empty. It's a .NET design patter to return a special field when you want to check if structure creation was successful. Avoid out parameters when you can.
返回Point.Empty。当您想要检查结构创建是否成功时,返回特殊字段是一种.NET设计模式。尽可能避免输出参数。
public static readonly Point Empty
#9
1
A pattern that I'm experimenting with is returning a Maybe. It has the semantics of the TryParse pattern, but a similar signature to the null-return-on-error pattern.
我正在尝试的模式是返回一个Maybe。它具有TryParse模式的语义,但与null-return-on-error模式具有类似的签名。
I'm not yet convinced one way or the other, but I offer it for your collective consideration. It does have the benefit of not requiring a variable to defined before the method call to hold the out parameter at the call site of the method. It could also be extended with an Errors or Messages collection to indicate the reason for the failure.
我还不确定这种或那种方式,但我提供它供你集体考虑。它确实具有以下优点:在方法调用之前不需要定义变量以在方法的调用站点处保持out参数。它还可以使用Errors或Messages集合进行扩展,以指示失败的原因。
The Maybe class looks something like this:
Maybe类看起来像这样:
/// <summary>
/// Represents the return value from an operation that might fail
/// </summary>
/// <typeparam name="T"></typeparam>
public struct Maybe<T>
{
T _value;
bool _hasValue;
public Maybe(T value)
{
_value = value;
_hasValue = true;
}
public Maybe()
{
_hasValue = false;
_value = default(T);
}
public bool Success
{
get { return _hasValue; }
}
public T Value
{
get
{ // could throw an exception if _hasValue is false
return _value;
}
}
}
#10
0
I would say best practice is a return value means success, and an exception means failure.
我会说最佳实践是返回值意味着成功,而异常意味着失败。
I see no reason in the examples you provided that you shouldn't be using exceptions in the event of a failure.
我认为您提供的示例中没有理由不在发生故障时使用异常。
#11
0
Using an exception is a bad idea in some cases (especially when writing a server). You would need two flavors of the method. Also look at the dictionary class for an indication of what you should do.
在某些情况下使用异常是一个坏主意(特别是在编写服务器时)。你需要两种方法。另请查看字典类,以了解您应该做什么。
// NB: A bool is the return value.
// This makes it possible to put this beast in if statements.
public bool TryCalculatePoint(... out Point result) { }
public Point CalculatePoint(...)
{
Point result;
if(!TryCalculatePoint(... out result))
throw new BogusPointException();
return result;
}
Best of both worlds!
两全其美!
#12
0
The bool TrySomething() is at least a practice, which works ok for .net's parse methods, but I don't think I like it in general.
bool TrySomething()至少是一种练习,适用于.net的解析方法,但我认为我不喜欢它。
Throwing an exception is often a good thing, though it should not be used for situations you would expect to happen in many normal situations, and it has an associated performance cost.
抛出异常通常是一件好事,但它不应该用于您在许多正常情况下预期会发生的情况,并且它具有相关的性能成本。
Returning null when possible is in most cases ok, when you don't want an exception.
在大多数情况下,如果不需要异常,则在可能的情况下返回null。
However - your approach is a bit procedural - what about creating something like a PointCalculator class - taking the required data as parameters in the constructor? Then you call CalculatePoint on it, and access the result through properties (separate properties for Point and for Success).
但是 - 你的方法有点过程 - 如何创建类似PointCalculator类的东西 - 将所需的数据作为构造函数中的参数?然后在其上调用CalculatePoint,并通过属性访问结果(Point和for Success的单独属性)。
#13
0
You don't want to be throwing exceptions when there is something expected happening, as @Kevin stated exceptions are for exceptional cases.
当有预期的事情发生时,你不希望抛出异常,因为@Kevin声明异常是针对例外情况。
You should return something that is expected for the 'failure', generally null is my choice of bad return.
你应该返回一些预期的'失败',通常是我选择的不良回报。
The documentation for your method should inform the users of what to expect when the data does not compute.
您的方法的文档应该告知用户数据不计算时会发生什么。
#14
0
We once wrote an entire Framework where all the public methods either returned true (executed successfully) or false (an error occurred). If we needed to return a value we used output parameters. Contrary to popular belief, this way of programming actually simplified a lot of our code.
我们曾经写过一个完整的框架,其中所有公共方法都返回true(成功执行)或false(发生错误)。如果我们需要返回一个值,我们使用输出参数。与流行的看法相反,这种编程方式实际上简化了我们的许多代码。
#15
0
Well with Point, you can send back Point.Empty as a return value in case of failure. Now all this really does is return a point with 0 for the X and Y value, so if that can be a valid return value, I'd stay away from that, but if your method will never return a (0,0) point, then you can use that.
使用Point,您可以在发生故障时将Point.Empty作为返回值发回。现在这一切真的是返回一个0和X值的点,所以如果它可以是一个有效的返回值,我会远离它,但如果你的方法永远不会返回(0,0)点,那么你可以使用它。
#16
0
Sorry, I just remembered the Nullable type, you should look at that. I am not too sure what the overhead is though.
对不起,我只记得Nullable类型,你应该看看。我不太确定开销是多少。
#1
24
Personally, I think I'd use the same idea as TryParse() : using an out parameter to output the real value, and returning a boolean indicating whether the call was successful or not
就个人而言,我认为我使用与TryParse()相同的想法:使用out参数输出实际值,并返回一个布尔值,指示调用是否成功
public bool CalculatePoint(... out Point result);
public bool CalculatePoint(... out point result);
I am not a fan of using exception for "normal" behaviors (if you expect the function not to work for some entries).
我不喜欢为“正常”行为使用异常(如果您希望该函数不适用于某些条目)。
#2
7
Why would they fail? If it's because of something the caller has done (i.e. the arguments provided) then throwing ArgumentException is entirely appropriate. A Try[...] method which avoids the exception is fine.
他们为什么会失败?如果是因为调用者所做的事情(即提供的参数),那么抛出ArgumentException是完全合适的。一个避免异常的Try [...]方法很好。
I think it's a good idea to provide the version which throws an exception though, so that callers who expect that they will always provide good data will receive a suitably strong message (i.e. an exception) if they're ever wrong.
我认为提供引发异常的版本是一个好主意,因此,如果他们错了,那么期望他们将始终提供良好数据的呼叫者将收到适当强烈的消息(即异常)。
#3
5
Another alternative is to throw an exception. However, you generally only want to throw exceptions in "exceptional cases".
另一种方法是抛出异常。但是,您通常只想在“例外情况”中抛出异常。
If the failure cases are common (and not exceptional), then you've already listed out your two options. EDIT: There may be a convention in your project as how to handle such non-exceptional cases (whether one should return success or the object). If there is no existing convention, then I agree with lucasbfr and suggest you return success (which agrees with how TryParse(...) is designed).
如果失败案例很常见(并非例外),那么您已经列出了两个选项。编辑:您的项目中可能有一个约定如何处理此类非特殊情况(无论是应该返回成功还是对象)。如果没有现有的约定,那么我同意lucasbfr并建议你返回成功(这与TryParse(...)的设计方式一致)。
#4
2
If the failure is for a specific reason then I think its ok to return null, or bool and have an out parameter. If however you return null regardless of the failure then I don't recommend it. Exceptions provide a rich set of information including the reason WHY something failed, if all you get back is a null then how do you know if its because the data is wrong, you've ran out of memory or some other weird behavior.
如果失败是出于特定原因,那么我认为可以返回null,或者bool并且有一个out参数。但是,如果无论失败都返回null,那么我不推荐它。异常提供了丰富的信息,包括为什么出现故障的原因,如果你回来的都是null,那么你怎么知道它是否因为数据错误,你的内存不足或其他一些奇怪的行为。
Even in .net the TryParse has a Parse brother so that you can get the exception if you want to.
即使在.net中,TryParse也有一个Parse兄弟,所以如果你愿意,你可以获得异常。
If I provided a TrySomething method I would also provide a Something method that threw an exception in the event of failure. Then it's up to the caller.
如果我提供了TrySomething方法,我还会提供一个Something方法,在发生故障时抛出异常。然后由呼叫者决定。
#5
1
The model I've used is the same one MS uses with the TryParse methods of various classes.
我使用的模型与MS使用的模型与各种类的TryParse方法相同。
Your original code:
public Point CalculatePoint(... out Boolean boSuccess);
public List CalculateListOfPoints(... out Boolean boSuccess);
你原来的代码:public Point CalculatePoint(... out Boolean boSuccess); public List CalculateListOfPoints(... out Boolean boSuccess);
Would turn into public bool CalculatePoint(... out (or ref) Point CalculatedValue);
public bool CalculateListOfPoints(... out (or ref) List CalculatedValues);
会变成公共bool CalculatePoint(... out(或ref)Point CalculatedValue); public bool CalculateListOfPoints(... out(或ref)List CalculatedValues);
Basically you make the success/failure the return value.
基本上,您将成功/失败作为返回值。
#6
1
To summarise there are a couple of approaches you can take:
总结一下,您可以采取以下几种方法:
- When the return type is a value-type, like Point, use the Nullable feature of C# and return a Point? (aka Nullable), that way you can still return null on a failure
- Throw an exception when there's a failure. The whole argument/discussion regarding what is and isn't "exceptional" is a moot point, it's your API, you decide what's exceptional behaviour.
- Adopt a model similar to that implemented by Microsoft in the base types like Int32, provide a CalculatePoint and TryCalculatePoint (int32.Parse and int32.TryParse) and have one throw and one return a bool.
- Return a generic struct from your methods that has two properties, bool Success and GenericType Value.
当返回类型是一个值类型,如Point时,使用C#的Nullable特性并返回一个Point? (又名Nullable),这样你就可以在失败时返回null
发生故障时抛出异常。关于什么是“特殊”和不是“特殊”的整个论点/讨论是一个有争议的问题,它是你的API,你决定什么是特殊行为。
采用类似于Microsoft在Int32等基类型中实现的模型,提供一个CalculatePoint和TryCalculatePoint(int32.Parse和int32.TryParse)并且有一个throw和一个返回bool。
从具有两个属性bool Success和GenericType Value的方法返回一个通用结构。
Dependent on the scenario I tend to use a combination of returning null or throwing an exception as they seem "cleanest" to me and fit best with the existing codebase at the company I work for. So my personal best practice would be approaches 1 and 2.
根据场景我倾向于使用返回null或抛出异常的组合,因为它们对我来说似乎“最干净”并且最适合我工作的公司的现有代码库。所以我个人的最佳实践是方法1和方法2。
#7
1
It mostly depends on the behavior of your methods and their usage.
它主要取决于您的方法的行为及其用法。
If failure is common and non-critical, then have your methods return a boolean indicating their success and use an out parameter to convey the result. Looking up a key in a hash, attempting to read data on a non-blocking socket when no data is available, all these examples fall in that category.
如果失败是常见且非关键的,那么让您的方法返回一个指示其成功的布尔值,并使用out参数来传达结果。查找哈希中的密钥,在没有数据可用时尝试读取非阻塞套接字上的数据,所有这些示例都属于该类别。
If failure is unexpected, return directly the result and convey errors with exceptions. Opening a file read-only, connecting to a TCP server, are good candidates.
如果失败是意外的,则直接返回结果并传达异常错误。以只读方式打开文件,连接到TCP服务器,是很好的选择。
And sometimes both ways make sense...
有时两种方式都有意义......
#8
1
Return Point.Empty. It's a .NET design patter to return a special field when you want to check if structure creation was successful. Avoid out parameters when you can.
返回Point.Empty。当您想要检查结构创建是否成功时,返回特殊字段是一种.NET设计模式。尽可能避免输出参数。
public static readonly Point Empty
#9
1
A pattern that I'm experimenting with is returning a Maybe. It has the semantics of the TryParse pattern, but a similar signature to the null-return-on-error pattern.
我正在尝试的模式是返回一个Maybe。它具有TryParse模式的语义,但与null-return-on-error模式具有类似的签名。
I'm not yet convinced one way or the other, but I offer it for your collective consideration. It does have the benefit of not requiring a variable to defined before the method call to hold the out parameter at the call site of the method. It could also be extended with an Errors or Messages collection to indicate the reason for the failure.
我还不确定这种或那种方式,但我提供它供你集体考虑。它确实具有以下优点:在方法调用之前不需要定义变量以在方法的调用站点处保持out参数。它还可以使用Errors或Messages集合进行扩展,以指示失败的原因。
The Maybe class looks something like this:
Maybe类看起来像这样:
/// <summary>
/// Represents the return value from an operation that might fail
/// </summary>
/// <typeparam name="T"></typeparam>
public struct Maybe<T>
{
T _value;
bool _hasValue;
public Maybe(T value)
{
_value = value;
_hasValue = true;
}
public Maybe()
{
_hasValue = false;
_value = default(T);
}
public bool Success
{
get { return _hasValue; }
}
public T Value
{
get
{ // could throw an exception if _hasValue is false
return _value;
}
}
}
#10
0
I would say best practice is a return value means success, and an exception means failure.
我会说最佳实践是返回值意味着成功,而异常意味着失败。
I see no reason in the examples you provided that you shouldn't be using exceptions in the event of a failure.
我认为您提供的示例中没有理由不在发生故障时使用异常。
#11
0
Using an exception is a bad idea in some cases (especially when writing a server). You would need two flavors of the method. Also look at the dictionary class for an indication of what you should do.
在某些情况下使用异常是一个坏主意(特别是在编写服务器时)。你需要两种方法。另请查看字典类,以了解您应该做什么。
// NB: A bool is the return value.
// This makes it possible to put this beast in if statements.
public bool TryCalculatePoint(... out Point result) { }
public Point CalculatePoint(...)
{
Point result;
if(!TryCalculatePoint(... out result))
throw new BogusPointException();
return result;
}
Best of both worlds!
两全其美!
#12
0
The bool TrySomething() is at least a practice, which works ok for .net's parse methods, but I don't think I like it in general.
bool TrySomething()至少是一种练习,适用于.net的解析方法,但我认为我不喜欢它。
Throwing an exception is often a good thing, though it should not be used for situations you would expect to happen in many normal situations, and it has an associated performance cost.
抛出异常通常是一件好事,但它不应该用于您在许多正常情况下预期会发生的情况,并且它具有相关的性能成本。
Returning null when possible is in most cases ok, when you don't want an exception.
在大多数情况下,如果不需要异常,则在可能的情况下返回null。
However - your approach is a bit procedural - what about creating something like a PointCalculator class - taking the required data as parameters in the constructor? Then you call CalculatePoint on it, and access the result through properties (separate properties for Point and for Success).
但是 - 你的方法有点过程 - 如何创建类似PointCalculator类的东西 - 将所需的数据作为构造函数中的参数?然后在其上调用CalculatePoint,并通过属性访问结果(Point和for Success的单独属性)。
#13
0
You don't want to be throwing exceptions when there is something expected happening, as @Kevin stated exceptions are for exceptional cases.
当有预期的事情发生时,你不希望抛出异常,因为@Kevin声明异常是针对例外情况。
You should return something that is expected for the 'failure', generally null is my choice of bad return.
你应该返回一些预期的'失败',通常是我选择的不良回报。
The documentation for your method should inform the users of what to expect when the data does not compute.
您的方法的文档应该告知用户数据不计算时会发生什么。
#14
0
We once wrote an entire Framework where all the public methods either returned true (executed successfully) or false (an error occurred). If we needed to return a value we used output parameters. Contrary to popular belief, this way of programming actually simplified a lot of our code.
我们曾经写过一个完整的框架,其中所有公共方法都返回true(成功执行)或false(发生错误)。如果我们需要返回一个值,我们使用输出参数。与流行的看法相反,这种编程方式实际上简化了我们的许多代码。
#15
0
Well with Point, you can send back Point.Empty as a return value in case of failure. Now all this really does is return a point with 0 for the X and Y value, so if that can be a valid return value, I'd stay away from that, but if your method will never return a (0,0) point, then you can use that.
使用Point,您可以在发生故障时将Point.Empty作为返回值发回。现在这一切真的是返回一个0和X值的点,所以如果它可以是一个有效的返回值,我会远离它,但如果你的方法永远不会返回(0,0)点,那么你可以使用它。
#16
0
Sorry, I just remembered the Nullable type, you should look at that. I am not too sure what the overhead is though.
对不起,我只记得Nullable类型,你应该看看。我不太确定开销是多少。