【发布时间】:2013-05-30 05:40:54
【问题描述】:
设置
我有一个原型类TypedString<T>,它试图“强类型”(可疑的含义)某个类别的字符串。它使用 curiously recurring template pattern (CRTP) 的 C# 类比。
class TypedString<T>
public abstract class TypedString<T>
: IComparable<T>
, IEquatable<T>
where T : TypedString<T>
{
public string Value { get; private set; }
protected virtual StringComparison ComparisonType
{
get { return StringComparison.Ordinal; }
}
protected TypedString(string value)
{
if (value == null)
throw new ArgumentNullException("value");
this.Value = Parse(value);
}
//May throw FormatException
protected virtual string Parse(string value)
{
return value;
}
public int CompareTo(T other)
{
return string.Compare(this.Value, other.Value, ComparisonType);
}
public bool Equals(T other)
{
return string.Equals(this.Value, other.Value, ComparisonType);
}
public override bool Equals(object obj)
{
return obj is T && Equals(obj as T);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public override string ToString()
{
return Value;
}
}
TypedString<T> 类现在可用于在整个项目中定义一堆不同的“字符串类别”时消除代码重复。该类的一个简单用法示例是定义一个Username 类:
class Username(示例)
public class Username : TypedString<Username>
{
public Username(string value)
: base(value)
{
}
protected override string Parse(string value)
{
if (!value.Any())
throw new FormatException("Username must contain at least one character.");
if (!value.All(char.IsLetterOrDigit))
throw new FormatException("Username may only contain letters and digits.");
return value;
}
}
现在,这让我可以在整个项目中使用 Username 类,无需检查用户名的格式是否正确 - 如果我有 Username 类型的表达式或变量,这是保证 正确(或为空)。
场景 1
string GetUserRootDirectory(Username user)
{
if (user == null)
throw new ArgumentNullException("user");
return Path.Combine(UsersDirectory, user.ToString());
}
我不必担心此处用户字符串的格式 - 我已经知道它的类型本质上是正确的。
场景 2
IEnumerable<Username> GetFriends(Username user)
{
//...
}
在这里,调用者仅根据类型就知道它得到了什么作为返回。 IEnumerable<string> 需要阅读方法或文档的详细信息。更糟糕的是,如果有人要更改 GetFriends 的实现,从而引入错误并产生无效的用户名字符串,则该错误可能会默默地传播给方法的调用者并造成各种破坏。这个类型很好的版本可以防止这种情况发生。
场景 3
System.Uri 是 .NET 中的一个类示例,它只不过是包装了一个字符串,该字符串具有大量格式约束和用于访问有用部分的辅助属性/方法。所以这是一个证据,证明这种方法并不完全疯狂。
问题
我想这种事情以前已经做过了。我已经看到了这种方法的好处,不需要再说服自己了。
我可能会遗漏什么缺点吗?
以后有什么办法可以反过来咬我吗?
【问题讨论】:
-
对我来说,这只是一个不同名称的面向对象编程。如果
UserName编写正确,TypedString<UserName>或UserName类在功能上可以相同——TypedString 只是为您提供了一个强制继承模式。 -
@TimothyShields:在一般意义上同意 Meters 示例。但是,如果您正在编写单位转换程序或科学软件(月球着陆器模块!?-:)),那么像 Meters 类之类的东西将非常有用和有保证。它会阻止某人在需要 Meters 的情况下使用 Miles 实例。或者更好的是,通过一个小的操作员重载它可以自动将英里转换为米。关键是,根据需要使用(或滥用)数据类型。
-
“我想这种事情以前已经做过了。我已经看到了这种方法的好处,不需要再说服自己了。” - 我没有看到在不同的“类”周围喷射字符串验证代码的好处,这些“类”除了验证字符串之外真的没有其他行为。如果我的任务是维护这种废话,我会很生气地发现这些字符串验证没有在序列化/反序列化边界处处理。
-
我相信首选的命名法是“字符串类型”
-
@TimothyShields - 我没有投反对票。我不认为这是一个坏问题。我只是不认为这种方法有用。 YMMV。
标签: c# string design-patterns types