我为流经我们系统的各种字符串 ID 创建了一个强类型、不可变的包装类
抽象 BaseId 类:
(为简洁起见,省略了一些错误检查和格式化......)
public abstract class BaseId
{
// Gets the type name of the derived (concrete) class
protected abstract string TypeName { get; }
protected internal string Id { get; private set; }
protected BaseId(string id) { Id = id; }
// Called by T.Equals(T) where T is a derived type
protected bool Equals(BaseId other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return String.Equals(Id, other.Id);
}
// warning CS0660 (see comment #1 below)
//public override bool Equals(object obj) { return base.Equals(obj); }
public override int GetHashCode()
{
return TypeName.GetHashCode() * 17 + Id.GetHashCode();
}
public override string ToString()
{
return TypeName + ":" + Id;
}
// All T1 == T2 comparisons come here (where T1 and T2 are one
// or more derived types)
public static bool operator ==(BaseId left, BaseId right)
{
// Eventually calls left.Equals(object right), which is
// overridden in the derived class
return Equals(left, right);
}
public static bool operator !=(BaseId left, BaseId right)
{
// Eventually calls left.Equals(object right), which is
// overridden in the derived class
return !Equals(left, right);
}
}
我的目标是在基类中保留尽可能多的实现,以便派生类很小,主要/完全由样板代码组成。
示例具体 DerivedId 类:
请注意,此派生类型没有定义自己的其他状态。它的目的仅仅是创建一个强类型。
public sealed class DerivedId : BaseId, IEquatable<DerivedId>
{
protected override string TypeName { get { return "DerivedId"; } }
public DerivedId(string id) : base(id) {}
public bool Equals(DerivedId other)
{
// Method signature ensures same (or derived) types, so
// defer to BaseId.Equals(object) override
return base.Equals(other);
}
// Override this so that unrelated derived types (e.g. BarId)
// NEVER match, regardless of underlying Id string value
public override bool Equals(object obj)
{
// Pass obj or null for non-DerivedId types to our
// Equals(DerivedId) override
return Equals(obj as DerivedId);
}
// warning CS0659 (see comment #2 below)
//public override int GetHashCode() { return base.GetHashCode(); }
}
每个类都生成一个编译器警告:
不覆盖 BaseId 中的 Object.Equals(object o) 会产生编译警告:
warning CS0660: 'BaseId' defines operator == or operator != but does not override Object.Equals(object o)
但如果我实现 BaseId.Equals(object o),它只会调用 Object.Equals(object o) 中的基类实现。无论如何,我不知道这将如何被调用;它总是在派生类中被覆盖,并且那里的实现不会调用这个实现。不覆盖 DerivedId 中的 BaseId.GetHashCode() 会生成编译警告:
warning CS0659: 'DerivedId' overrides Object.Equals(object o) but does not override Object.GetHashCode()
这个派生类没有附加状态,所以在 DerivedId.GetHashCode() 的实现中我没有什么可做的,除了在 BaseId.GetHashCode 中调用基类实现()。
我可以抑制编译器警告或只实现方法并让它们调用基类实现,但我想确保我没有遗漏任何东西。
我这样做的方式有什么奇怪的吗,或者这只是你必须做的事情之一,以抑制对其他正确代码的警告?