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

C# 带有只读字段的TryParse模式/非默认构造函数,c#,C#,当人们有只读支持字段和非默认构造函数时,通常如何使用TryParse模式实现解析构造函数 下面是一个我正在谈论的人为的例子,以及我已经确定的模式,但它看起来很笨重。实际上,某些类型具有大量属性。当然,我可以创建一个接受n个ref参数的方法,进行解析,并以这种方式将它们连接起来,但在某些情况下,拥有一个包含15个参数的方法也是一件痛苦/难闻的事情 使用两个构造函数,再加上必须将try-parse的结果复制到解析构造函数中的只读字段,这有点异味 还有谁有更好的模式吗 编辑:提供更多上下文 我试图做的

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

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

使用两个构造函数,再加上必须将try-parse的结果复制到解析构造函数中的只读字段,这有点异味

还有谁有更好的模式吗

编辑:提供更多上下文

我试图做的是重构一个大型(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;
      }
   }
}

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


您有一个
TryParse
方法,它遵循C#/.NET应用程序的典型预期模式。按照Jon Skeet的建议进行更改,然后,如果您的用户想要将
字符串
解析为
,您当前的方法实际上不起作用-因为
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-parse的结果复制到解析构造函数中的只读字段,这有点异味

使用这种方法,您只需要一个构造函数——但是将值传递给构造函数并将其复制到对象中有什么不对呢?我觉得这很自然


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

我100%同意你的观点,构造函数应该尽可能少做。现在,构造函数实际上正在做所有的解析工作(遗留代码库),我正试图重构成一个纯粹的“只尝试解析”解决方案。说起来容易做起来难。@jasper:你可以用
struct
类型和
this=result来做一些技巧,但我认为这会增加复杂性,而不是简化事情。你得到的可能是你最好的赌注。因为只有在完成重构之前,才会这样做,所以这应该不是什么大问题。您应该将解析构造函数
标记为过时的
,这样人们就不会在编写新代码时尝试使用它。从来都不知道您可以在c#中使用该结构。我现在就要用过时的+TryParse。这一点上的例子完全是人为的,只要它像两个浮点解析一样简单就好了。在将参数直接传递给构造函数时,您是否仍然认为这适用于可能有10个以上参数的情况?@jasper:我可能会在此时创建一个单独的生成器类型。请参阅我的更新。我希望将来转到工厂类,因为某些解析相当复杂。我喜欢ParseResult的概念,并将借用该模式,它将非常适合这一点,因为有很多原因导致某些东西无法解析。