人们通常如何使用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;
}
}
}
答案 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
。