具有只读字段的TryParse模式/非默认构造函数

时间:2012-07-30 20:48:44

标签: c#

人们通常如何使用TryParse模式实现解析构造函数,当它们具有只读备份字段时,以及通常会进行解析的非默认构造函数?

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

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

其他人有更好的模式吗?

修改:提供更多背景信息

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

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

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

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;
      }
   }
}

2 个答案:

答案 0 :(得分:5)

您当前的方法并不真正起作用 - 因为float.Parse可以抛出异常。我会使用类似的东西:

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;
}

正如StriplingWarrior所说,我开始摆脱解析构造函数 - 无论如何你使用TryParse,也要添加Parse方法。

  

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

使用这种方法,你只需要一个构造函数 - 但是将值传递给构造函数并将它们复制到对象中有什么问题?这对我来说很自然。

或者,您可以使用我们在Noda Time中使用的方法,您可以在其中创建一个负责解析和格式化的完整单独对象,以及一个能够表示成功/失败的ParseResult<T>类型。解析,同时保留使用有关失败的有意义信息抛出异常的能力。就个人而言,我发现它比BCL模式好很多,虽然可以说我有偏见:)

答案 1 :(得分:4)

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

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