C#类型推理:如何正确定义方法上的约束

本文关键字:方法 约束 定义 何正确 类型 推理 | 更新日期: 2023-09-27 18:20:19

嗨,我很难让C#类型推理按我的意愿进行。我有一个非常具体的情况,我有很多风格的变量

ConcurrentDictionary<T, IDictionary<U, V> >

其中,T、U、V可以是一些随机类型,如long、int或其他类型。

我想写一个能处理这类变量的方法——尤其是检查它们的直方图。

所以我写了一个方法

public static IOrderedEnumerable<Tuple<int,int>> GetDictionaryHistogram<T, U, V, W>(T dictionary) where T : ConcurrentDictionary<U, IDictionary<V, W>>
{
    return dictionary.Select(p => p.Value.Count)
                     .GroupBy(p => p)
                     .Select(p => new Tuple<int, int>(p.Key, p.Count()))
                     .OrderBy(p => p.Item1);
}

但是当我尝试调用它时,C#给了我一个错误,它无法推断类型。例如类型的变量

ConcurrentDictionary<int,IDictionary<int, int> > foo;

我得到错误:

错误118方法的类型参数"Auditor.AuditorHelpers.GetDictionaryHistogram(T)"不能为根据用法推断。请尝试显式指定类型参数。

我做错了什么?

C#类型推理:如何正确定义方法上的约束

类型推断从参数形式参数类型。从未对约束进行过推断,因为约束不是方法的签名的一部分。

在您的情况下,类型推理必须始终失败;类型推断不可能推断U和V的类型,因为它们不出现在形式参数类型中。

大约有十几个人告诉我,我错误地认为这条规则是合理的,请参阅我关于这个主题的文章的评论。

类型参数T是不必要的。你应该只写

public static IOrderedEnumerable<Tuple<int,int>> GetDictionaryHistogram<U, V, W>(
    ConcurrentDictionary<U, IDictionary<V, W>> dictionary)

它应该可以正常工作。

您的约束类型(其中参数必须是特定类型)仅在少数情况下有用。最常见的是避免对实现接口的值类型进行装箱。比较这两种方法:

public static DoSomething(ISomeInterface thing) {}
public static DoSomething<T>(T thing) where T : ISomeInterface {}

当使用值类型参数调用第一个方法时,该参数将被装箱并强制转换为接口类型。

当使用值类型调用第二个方法时,泛型类型参数将替换为值类型,并且不会进行装箱。

我认为编译器说它无法计算出类型之间的依赖关系。

尝试做:

public static IOrderedEnumerable<Tuple<int,int>> GetDictionaryHistogram<U, V, W>(ConcurrentDictionary<U, IDictionary<V, W>> dictionary)
{
    return dictionary.Select(p => p.Value.Count)
                     .GroupBy(p => p)
                     .Select(p => new Tuple<int, int>(p.Key, p.Count()))
                     .OrderBy(p => p.Item1);
}