我正在使用一个简洁的小HashCode
实用程序,其中包含一些有助于快速生成哈希值的实例方法。我已经简化了这个问题,但基本上就是这样:
public struct HashCode
{
private readonly int _hashCode;
public HashCode(int hashCode) { _hashCode = hashCode; }
override int GetHashCode() => _hashCode;
public static HashCode Start => new HashCode(17);
public HashCode Hash(int integer) => new HashCode(unchecked(integer + hashCode * 31));
public HashCode Hash<T>(T value) where T : struct => Hash(value.GetHashCode());
public HashCode Hash(string value) => Hash(value?.GetHashCode() ?? 17);
public HashCode Hash<T>(T? nullable) where T : struct =>
Hash(nullable?.GetHashCode() ?? 17);
// Other reference types, user must explicitly specify a comparer
public HashCode Hash<T>(T obj, IEqualityComparer<T> comparer) =>
Hash(obj == null ? 17: comparer.GetHashCode(obj));
public static implicit operator int(HashCode hashCode) => hashCode.GetHashCode();
}
允许光滑的哈希实现,如:
class Person {
// ...
override GetHashCode() => HashCode.Start.Hash(name).Hash(age).Hash(...);
}
正如您所看到的,它可以避免装箱等。如果您直接对参考类型进行哈希处理,则必须指定一个比较器以确保您知道它是如何被哈希处理的。似乎合理
现在,我希望在我的一个项目中添加一些扩展方法(即而不复制和修改库),以便我可以轻松添加一些我自己经常使用的consice哈希函数类型,并使用完全相同的语法使用它们:
public static class HashCode_Extensions
{
public static HashCode Hash(this HashCode hc, DateRange range) =>
hc.Hash(range?.begin).Hash(range?.end);
public static HashCode Hash(this HashCode hc, IEnumerable<T> list) where T : struct =>
list.Aggregate(hc, (hc, elem) => hc.Hash(elem));
// etc...
}
我以为我太聪明了,大量的复制粘贴代码就会消失。
class Meeting {
// ...
override GetHashCode() => HashCode.Start.Hash(name).Hash(dateRange).Hash(invitees);
}
不幸的是,编译器正在选择我自己的泛型实例方法,即使我的方法是完美的,而泛型方法的类型约束不是
CS0453“DateRange”类型必须是非可空值类型才能在泛型类型的方法'HashCode.Hash(T)'
中将其用作参数'T'
显然,编译器已经确定Hash
的“最佳重载”是具有非满足泛型类型约束的那个。太糟糕了,因为我的扩展方法非常适合。
有没有什么方法可以欺骗编译器使用正确的方法而不必在调用Hash
时使用不同的函数名称或包含'dummy'参数?
如果我有一些向后兼容的方式来更改允许我的扩展方法被注意到的HashCode
库,我也会很高兴。 (我不想将自定义重载添加到基本库中,因为这些自定义类型当前不存在于其名称空间中)
答案 0 :(得分:0)
一个小技巧将起作用。创建一个这样的类:
public class RequireStruct<T> where T : struct { }
将其作为可选参数放在通用方法中,如下所示:
public struct HashCode
{
private readonly int _hashCode;
public HashCode Hash<T>(T value, RequireStruct<T> ignore = null) where T : struct => Hash(value.GetHashCode());
}
现在当你这样做时,它会选择你想要的扩展方法:
HashCode code = new HashCode();
code.Hash(new DateRange());
here被盗。