通常,域对象具有可以用内置类型表示的属性,但是其有效值是可以用该类型表示的值的子集。
在这些情况下,可以使用内置类型存储值,但是必须确保始终在输入点验证值,否则我们最终可能会使用无效值。
解决此问题的一种方法是将值存储为自定义struct
,该自定义具有private readonly
内置类型的单个后备字段,并且其构造函数会验证提供的值。然后,我们始终可以确保仅通过使用此struct
类型来使用经过验证的值。
我们还可以提供与底层内置类型之间的强制转换运算符,以便值可以作为底层类型无缝地进入和退出。
以一个例子为例,其中我们需要表示域对象的名称,并且有效值是长度在1到255个字符(含)之间的任何字符串。我们可以使用以下结构来表示:
public struct ValidatedName : IEquatable<ValidatedName>
{
private readonly string _value;
private ValidatedName(string name)
{
_value = name;
}
public static bool IsValid(string name)
{
return !String.IsNullOrEmpty(name) && name.Length <= 255;
}
public bool Equals(ValidatedName other)
{
return _value == other._value;
}
public override bool Equals(object obj)
{
if (obj is ValidatedName)
{
return Equals((ValidatedName)obj);
}
return false;
}
public static implicit operator string(ValidatedName x)
{
return x.ToString();
}
public static explicit operator ValidatedName(string x)
{
if (IsValid(x))
{
return new ValidatedName(x);
}
throw new InvalidCastException();
}
public static bool operator ==(ValidatedName x, ValidatedName y)
{
return x.Equals(y);
}
public static bool operator !=(ValidatedName x, ValidatedName y)
{
return !x.Equals(y);
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
public override string ToString()
{
return _value;
}
}
该示例显示了TO- string
投的implicit
,因为这可能永远不会失败,但在从- string
铸造的explicit
,因为这将引发无效值,但当然这些都可能是两种implicit
或explicit
。
还要注意,只能通过from的强制转换来初始化此结构string
,但是可以使用IsValid
static
方法预先测试这种强制转换是否会失败。
这似乎是强制验证可以用简单类型表示的域值的一种好模式,但是我看不到它经常使用或建议使用,而且我对原因很感兴趣。
所以我的问题是:您认为使用此模式的优点和缺点是什么?为什么?
如果您认为这是一个糟糕的模式,我想了解为什么以及您认为是最佳的选择。
注意:我最初是在Stack Overflow上问这个问题的,但由于主要基于观点(具有讽刺意味的是,它本身具有主观性)而被搁置了-希望它可以在这里获得更多的成功。
上面是原始文本,下面是一些想法,部分是对搁置之前在那里收到的答复的回应:
- 答案提出的主要观点之一是上述模式所需的样板代码数量,尤其是在需要许多此类代码时。但是,为了捍卫这种模式,可以使用模板在很大程度上将其自动化,并且实际上对我来说似乎还不错,但这只是我的观点。
- 从概念的角度来看,使用强类型语言(例如C#)仅将强类型原理应用于复合值,而不是将其扩展为可以由a实例表示的值,这似乎并不奇怪。内置类型?