【问题标题】:Naming and structure of a function函数的命名和结构
【发布时间】:2013-12-11 19:30:25
【问题描述】:

这是我第一次在这里发布问题,所以如果我做错了什么,请纠正我。我只是很难找到命名函数的正确方法。 我应该首先说我正在开发一个 Windows Phone 项目,并且使用的语言是 C#。 我有一个名为 Ride 的类,如下所示:

public class Ride
{
  public Destination {get; set;}
  public Arrival {get;set;}
  .... 
  public bool IsValid(ErrorLevel level = ErrorLevel.Throw)
  {
    try{
     if(something_is_not_valid)
        throw new SomeException("some message that should be displayed");
     return true; //if it gets here it means it's valid
    }
    catch{Exception){
      if(level == ErrorLevel.Throw) //if I want to throw the exception
         throw;
      return false; //return false, because it's not valid
    }
  }
}

我想了解您对 IsValid 函数的看法。我在我的代码中这样使用它:

public void DoSomethingWithARideOnlyIfItsValid(Ride ride){
   try{
     ride.IsValid();
     //if it gets here, it means
     //that the function didn't throw an error
     rideManager.DoSomething(ride);
   }
   catch(Exception ex){
     MessageBox.Show(ex.Message);
   }
}

所以 IsValid 函数可以接收可以是 Throw 或 Return 的 ErrorLevel 参数。在某些情况下,我只想查看函数返回什么,并将 ErrorLevel.Return 作为参数发送,但在大多数情况下,如果验证失败,我希望它与消息一起引发异常,以便我可以直接展示给用户。太臭了……所以我做错了什么。我想过将名称更改为 Validate,但这并没有让它变得更好。 另一种解决方案是使用一个属性 IsValid,它只会返回 true 或 false,以及一个函数 Validate(),如果出现问题,它将返回一条消息,以便我可以将其显示给用户。你有什么其他的建议? 谢谢!

【问题讨论】:

  • 如果太臭,开窗通风。你说的“太臭”是什么意思?你的意思只是命名约定? “ThrowIfInvalid()”怎么样?
  • 您听说过“代码气味”吗? en.wikipedia.org/wiki/Code_smell 应该不错,但我也希望它在某些情况下不抛出异常。我说的不仅仅是名字。如果其他人想使用该函数,他们会对发送给函数的枚举参数感到困惑,并且在某些情况下它返回 true 或 false,并且在某些情况下会引发错误。
  • 不知道“代码异味”这个词。不得不承认,“代码味道”是个好东西:)
  • 在保护块或验证失败时抛出异常的保护或验证函数并不少见,并且主要是为了方便而提供的。如果提供了这样的方法,最好也提供一个不抛出而是返回布尔值(或“不通过”的另一个适当指示)的变体,因为异常处理对于经常执行的代码来说可能是昂贵的或者是非常时间紧迫的;好吧,有时你不希望代码中到处都是 try-catch 混乱......

标签: c# oop coding-style


【解决方案1】:

我会创建一个类

public class ReturnClass
{
    public ReturnClass()
    {
        IsOk = true;
    }

    public bool IsOk { get; set; }
    public string ErrorText { get; set; }
}

然后做ReturnClass类型的Validate函数的返回值。在 validate 函数中,如果发生错误,将 IsOk 设置为 false,并将错误文本写入属性 ErrorText。

【讨论】:

  • 我同意这一点。例外是相当昂贵的。谓词存在 TryParse-Pattern 是有原因的。
  • 我已经有了这样一个带有 IsSuccessful 和 Message 的类,但我只将它用于发出 Web 请求的函数。我没有将它用于 IsValid 函数的原因是因为我不太了解干净代码中异常的好坏。我想我会使用这种方法!非常感谢!
  • 我认为这不是一个好的解决方案。它违背了语言并使代码复杂化。异常并不昂贵,担心它绝对是过早的优化。它们服务于一个非常真实的目的,标志着一个例外情况,这也是整个 .NET 框架使用它们的原因。 Microsoft 的建议是使用异常,并且不要返回错误代码或根据选项决定抛出:blogs.msdn.com/b/kcwalina/archive/2005/03/16/396787.aspx 请参阅下面的答案以了解我认为更好的解决方案。
  • @Mfanto:例外是昂贵的,并且不太适合“测试者-执行者”模式(只需阅读您链接的博客文章;)。但我同意,在许多情况下所涉及的成本微不足道,并且被使用例外的好处所抵消。
  • 我更多地链接到那里以获得一般建议,但我不同意 tester-doer 和 TryParse 与性能相关的论点。 Parse() 和 TryParse() 之间有两个非常不同的用例,选择其中一个来提高性能似乎很愚蠢。无论如何,如果异常是性能问题,那么您使用异常是错误的。
【解决方案2】:

我认为你应该摆脱所有 ErrorLevel 的东西。它使代码复杂化,并且很难说出该方法的作用。

IsValid() 对我来说似乎应该返回一个是/否的答案,并且只有在出现问题时才抛出异常。

public class Ride
{
    public Destination {get; set;}
    public Arrival {get;set;}
    .... 

    public bool IsValid()
    {
        if (Arrival == null)
        {
            throw new ArgumentException("Arrival");
        }

        return DoSomethingToValidateDestionationAndArrival();
    }
}

然后你的调用者看起来像:

public void DoSomethingWithARideOnlyIfItsValid(Ride ride)
{
    try
    {
        if (ride.IsValid() == false)
         {
             throw new Exception("The ride is invalid");
         }

         //if it gets here, it means
         //that the function didn't throw an error
         rideManager.DoSomething(ride);
    }
    catch(Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

现在您可以访问导致错误的真正异常(是参数错误,表明程序有问题),还是用户提供的无效 Ride。代码也更容易阅读。

【讨论】:

    【解决方案3】:

    IsValid 真的必须有 try;catch 吗?难道它不只是抛出,因为 IsValid 的任何调用方法都应该尝试一下;抓住它,因为你想用消息框显示错误。

    public class Ride
    {
      public Destination {get; set;}
      public Arrival {get;set;}
      .... 
      public void Validate(ErrorLevel level = ErrorLevel.Throw)
      {
         if(level == ErrorLevel.Throw) //if I want to throw the exception
             throw;
         if(something_is_not_valid)
            throw new SomeException("some message that should be displayed");
      }
    }
    

    然后在调用者上做这样的事情?

    public void DoSomethingWithARideOnlyIfItsValid(Ride ride){
       try{
         ride.Validate();
         rideManager.DoSomething(ride);
       }
       catch(SomeException ex){
          //...
       }
       catch(Exception ex){
         MessageBox.Show(ex.Message);
       }
    }
    

    或者说真的,DoSomething(ride) 真的是做什么的?是为了省钱吗?它只是验证什么?这取决于上下文。你在验证什么?检查属性是否为空?如果是这种情况,那么您可以将它们移动到属性的设置器中,因为它们具有支持字段并将验证移动到 DoSomething(ride);

    【讨论】:

    • 有一个 RideManager 类,类似于 Ride 类的 CRUD。如果我有一个函数 CreateRide(Ride Ride),那么我应该检查这个函数是否骑行有效,甚至可能对骑行进行一些更改,然后将其传递给 RideService,它会发出创建骑行的 Web 请求.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    • 1970-01-01
    • 2018-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多