設定
TypedString<T>
特定のカテゴリの文字列を「強く型付け」(疑わしい意味) しようとするプロトタイプ クラスがあります。これは、奇妙に繰り返されるテンプレート パターン (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
、プロジェクト全体でクラスを使用できるようになり、ユーザー名が正しくフォーマットされているかどうかを確認する必要がなくなりました。 type の式または変数がある場合、正しい (または null) である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 のクラスの例です。これは、文字列の有用な部分にアクセスするための膨大な数の書式設定制約とヘルパー プロパティ/メソッドを持つ文字列をラップするだけです。これは、このアプローチがまったくおかしくないという証拠の 1 つです。
質問
このようなことは以前にも行われたことがあると思います。私はすでにこのアプローチの利点を理解しており、これ以上自分自身を納得させる必要はありません.
私が見逃しているかもしれない欠点はありますか?
これが後で私を噛むために戻ってくる可能性がある方法はありますか?