具有不满足类型约束的泛型方法隐藏了一个扩展方法
Generic Method with Unsatisfied Type Constraint is Hiding an Extension Method
我正在使用一个简洁的小 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 The type 'DateRange' must be a non-nullable value type in order to use it as parameter 'T' in the generic type of method 'HashCode.Hash(T)'
显然编译器已经决定 Hash
的 "best overload" 是不满足泛型类型约束的那个。太糟糕了,因为我的扩展方法非常适合。
有什么方法可以诱使编译器使用正确的方法,而不必求助于使用不同的函数名称或在我对 Hash
的调用中包含 'dummy' 个参数?
如果有一些向后兼容的方式让我更改 HashCode
库,让我的扩展方法受到关注,我也会很高兴。 (我不想将我的自定义重载添加到基础库中,因为这些自定义类型当前不存在于它的命名空间中)
一个小技巧就可以了。像这样创建一个 class:
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.
偷来的
我正在使用一个简洁的小 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 The type 'DateRange' must be a non-nullable value type in order to use it as parameter 'T' in the generic type of method 'HashCode.Hash(T)'
显然编译器已经决定 Hash
的 "best overload" 是不满足泛型类型约束的那个。太糟糕了,因为我的扩展方法非常适合。
有什么方法可以诱使编译器使用正确的方法,而不必求助于使用不同的函数名称或在我对 Hash
的调用中包含 'dummy' 个参数?
如果有一些向后兼容的方式让我更改 HashCode
库,让我的扩展方法受到关注,我也会很高兴。 (我不想将我的自定义重载添加到基础库中,因为这些自定义类型当前不存在于它的命名空间中)
一个小技巧就可以了。像这样创建一个 class:
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.
偷来的