关于c#:如何表明方法不成功

How to indicate that a method was unsuccessful

我有几个类似的方法,例如calculatePoint(…)和calculateListofPoints(…)。有时,他们可能不会成功,需要向调用者表明这一点。对于CalculateListOfPoints,它返回一个通用列表,我可以返回一个空列表,并要求调用者检查它;但是,点是一个值类型,因此我不能在那里返回空值。

理想情况下,我希望方法"看起来"相似;一种解决方案是将它们定义为

1
2
public Point CalculatePoint(... out Boolean boSuccess);
public List<Point> CalculateListOfPoints(... out Boolean boSuccess);

或者返回一个点?对于CalculatePoint,返回空以指示失败。这意味着必须将类型转换回不可为空的类型,但这似乎太过分了。

另一种方法是返回Boolean Bosuccess,将结果(点或列表)作为"out"参数,并调用它们TryToCalculatePoint或其他…

什么是最佳实践?

编辑:我不想使用例外流控制!失败有时是意料之中的。


就我个人而言,我想我会使用与typarse()相同的想法:使用out参数输出实际值,并返回一个布尔值,指示调用是否成功。

public bool CalculatePoint(... out Point result);

我不喜欢将异常用于"正常"行为(如果您希望函数对某些条目不起作用)。


他们为什么会失败?如果是因为调用者做了什么(即提供的参数),那么抛出ArgumentException是完全合适的。可以使用try[…]方法避免异常。

我认为提供引发异常的版本是一个好主意,这样,期望始终提供良好数据的呼叫者在出错时会收到适当的强消息(即异常)。


另一种选择是抛出异常。但是,您通常只希望在"异常情况"中抛出异常。

如果失败案例很常见(并且不是例外),那么您已经列出了两个选项。编辑:在您的项目中可能有一个惯例,即如何处理这些非异常情况(一个人应该返回成功还是对象)。如果没有现有的约定,那么我同意Lucasbfr并建议您返回成功(这与Terparse(…)的设计方式一致)。


如果失败是由于特定的原因,那么我认为返回空值或bool并有一个out参数是可以的。但是,如果不管失败如何都返回空值,那么我不建议这样做。异常提供了一组丰富的信息,包括一些失败的原因,如果您得到的全部是一个空值,那么您如何知道它是否是因为数据错误、内存不足或其他一些奇怪的行为。

即使在.NET中,台盼也有一个解析兄弟,这样您可以在需要时获取异常。

如果我提供一个Trysometing方法,我还将提供一个在失败时引发异常的方法。然后由来电者决定。


它主要取决于方法的行为和它们的用法。

如果失败是常见的和非关键的,那么让您的方法返回一个指示其成功的布尔值,并使用out参数来传递结果。在散列中查找键,在没有可用数据的情况下尝试读取非阻塞套接字上的数据,所有这些示例都属于该类别。

如果失败是意外的,则直接返回结果并传递错误和异常。以只读方式打开文件(连接到TCP服务器)是很好的选择。

有时这两种方法都有意义…


我使用的模型与MS使用的不同类的台盼色方法相同。

您的原始代码:公共点计算点(…输出布尔值bosuccess);公共列表CalculateListofPoints(…输出布尔值bosuccess);

会变成公共布尔计算点(…输出(或参考)点计算值;公共bool calculateListofPoints(…列出(或参考)计算值;

基本上,您将成功/失败作为返回值。


总结一下,您可以采取以下几种方法:

  • 当返回类型是值类型时,如point,使用c的可空特性并返回一个点?(也叫nullable),这样失败时仍然可以返回null
  • 失败时抛出异常。关于什么是"异常"和什么不是"异常"的整个争论/讨论是一个无意义的观点,它是您的API,您决定什么是异常行为。
  • 在Int32等基本类型中采用类似于Microsoft实现的模型,提供CalculatePoint和TrycalculatePoint(Int32.Parse和Int32.Tryparse),并有一个throw和一个return一个bool。
  • 从方法中返回具有两个属性的泛型结构:bool success和genericType值。
  • 根据场景的不同,我倾向于使用返回空值或抛出异常的组合,因为它们对我来说是"最干净的",并且最适合我工作的公司中现有的代码库。所以我个人的最佳实践是方法1和2。


    返回点。空。当您想检查结构创建是否成功时,返回一个特殊字段是.NET设计模式。尽可能避免输出参数。

    1
    public static readonly Point Empty


    我正在试验的一个模式是返回一个可能。它具有台盼模式的语义,但与错误模式的空返回类似。

    我还没有以这种或那种方式说服你,但我提出这个建议是为了你的集体考虑。它的好处是不需要在方法调用之前定义一个变量,以便在方法的调用站点保存out参数。它还可以通过错误或消息集合进行扩展,以指示失败的原因。

    可能的类如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    /// <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;
                }
        }
    }

    对不起,我刚刚记起了可以为空的类型,你应该看看。不过,我不太确定开销是多少。


    我们曾经编写了一个完整的框架,其中所有公共方法都返回了true(成功执行)或false(发生错误)。如果需要返回值,则使用输出参数。与流行的观点相反,这种编程方式实际上简化了我们的许多代码。


    我会说,最佳实践是回报值意味着成功,而例外意味着失败。

    在您提供的示例中,我看不到在发生故障时不应使用异常的原因。


    使用point,你可以返回point.empty作为失败时的返回值。现在,所有这些实际上都是返回一个带有0的点作为x和y值,所以如果这是一个有效的返回值,我会远离它,但是如果你的方法永远不会返回一个(0,0)点,那么你可以使用它。


    bool trysomething()至少是一种实践,对于.NET的解析方法来说是可行的,但我不认为我一般喜欢它。

    抛出一个异常通常是一件好事,尽管它不应该用于您期望在许多正常情况下发生的情况,并且它有一个相关的性能成本。

    在大多数情况下,当不需要异常时,尽可能返回空值是可以的。

    但是,您的方法有点程序化——创建点计算器类之类的东西怎么样——将所需数据作为构造函数中的参数?然后对其调用calculatePoint,并通过属性访问结果(分别为point和success属性)。


    在某些情况下(尤其是在编写服务器时),使用异常是一个坏主意。您需要两种风格的方法。还要查看Dictionary类以了解应该做什么。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 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;
    }

    两全其美!


    您不希望在发生预期情况时抛出异常,正如@kevin所说的异常是针对异常情况的。

    你应该返回一些"失败"所期望的东西,通常空值是我选择的错误返回。

    您方法的文档应该告诉用户当数据不计算时会发生什么。