2

人们通常如何使用 TryParse 模式实现解析构造函数,当他们具有只读支持字段和非默认构造函数时,通常会进行解析?

下面是我正在谈论的一个人为的例子,以及我已经确定的模式,但它看起来很笨重。实际上,某些类型具有大量属性。当然,我可以创建一个采用n ref 参数的方法,进行解析,然后以这种方式将它们连接起来,但是在某些情况下拥有一个带有 15 个参数的方法也是一种痛苦/难闻的事情。

两个构造函数的想法,加上必须将 try 解析的结果复制到解析构造函数中的只读字段,这有点难闻。

其他人有更好的模式吗?

编辑:提供更多上下文

我正在尝试做的是重构一个大型(ish)代码库,它有许多类型,如下例所示,其中解析了提供给构造函数的字符串参数。现在,所有的代码都使用了构造函数解析,而这个解析的逻辑都是在构造函数中完成的。混乱和麻烦。

我想做的第一件事是将这段代码从构造函数中移出,进入工厂方法(TryParse),但保留构造函数签名,因此我对代码库没有太多更改。从长远来看,有时间可以做一些更好的事情。

目前,困难在于保持现有代码的构造签名完整,同时允许新代码使用 TryParse 模式,并保留只读字段。如果我放宽只读字段,整个过程会更容易,但我宁愿不这样做。

public class Point
{
   private readonly float x, y;
   public float X { get { return x; } }
   public float Y { get { return y; } }

   public Point(string s)
   {
      Point result;

      if (TryParse(s, out result))
      {
         this.x = result.x;
         this.y = result.y;
      }
      else
      {
         throw new System.ArgumentException("cant parse");
      }
   }

   private Point(float x,float y) // for the sake of the example, this wouldnt have any use as public
   {
      this.x = x;
      this.y = y;
   }

   public static bool TryParse(string s,out Point result)
   {
      var numbers = s.Split(',');

      if(numbers.Length == 2)
      {
         result = new Point(float.Parse(numbers[0]),float.Parse(numbers[0]));
         return true;
      }
      else
      {
         result = null;
         return false;
      }
   }
}
4

2 回答 2

5

Your current approach doesn't really work - because float.Parse can throw an exception. I'd use something like:

public static bool TryParse(string s, out Point result)
{
   var numbers = s.Split(',');
   if (numbers.Length == 2)
   {
       float x, y;
       if (float.TryParse(numbers[0], out x) && 
           float.TryParse(numbers[1], out y))
       {
           result = new Point(x, y);
           return true;  
       }    
   }
   result = null;
   return false;
}

As StriplingWarrior says, I'd get rid of the parsing constructor to start with - if you're using TryParse anyway, add a Parse method too.

The idea of two constructors, plus having to copy the result of the try parse to the readonly fields in the parsing constructor smells a little.

Well with this approach, you only need one constructor - but what's wrong with passing values to a constructor and it copying them into the object? That seems natural to me.

Alternatively, you could use the approach we use in Noda Time where you create a whole separate object responsible for parsing and formatting, and a ParseResult<T> type which is able to represent the success/failure of a parse, while retaining the ability to throw an exception with meaningful information about the failure. Personally I find it a lot nicer than the BCL pattern, although arguably I'm biased :)

于 2012-07-30T20:51:58.677 回答
4

我通常尽量避免解析构造函数。有一种流行的观点是构造函数应该尽可能少做,并且通常只接受直接存储到字段中以供以后使用的参数。如果你想解析一个字符串,那不是构造函数的责任。

您有一个TryParse遵循 C#/.NET 应用程序的典型预期模式的方法。进行 Jon Skeet 建议的更改,然后希望您的用户在想要将 a 解析string为 a 时直接调用该方法Point

于 2012-07-30T20:51:24.417 回答