【问题标题】:Why can 'int' be treated as 'ushort' but not when passed as a parameter in an extension method and what's an elegant solution to it?为什么“int”可以被视为“ushort”,但在扩展方法中作为参数传递时却不能,什么是优雅的解决方案?
【发布时间】:2012-12-05 18:23:26
【问题描述】:

我有这个扩展方法:

public static bool In<T>(this T source, params T[] list)
{
    return list.Contains(source);
}

现在我需要对ushort 使用上述方法。当我尝试时

ushort p = 3;
if (p.In(1, 2, 3, 4, 5))
   return;

第一行将3 转换为ushort 井。但是当3作为参数传递时,我得到了错误

'ushort' 不包含'In' 的定义,并且最佳扩展方法重载'Extensions.In(T, params T[])' 有一些无效参数。

但这有效:

ushort p = 3;
if (Extensions.In(p, 1, 2, 3, 4, 5))
   return;

这很奇怪。

  1. 为什么它适用于第二个示例,而不适用于第一个示例?

  2. 在这方面有什么好的选择可以帮助我?由于shortushort 没有文字,我找不到比手动转换每个整数更简单的替代方法:

    ushort p = 3;
    if (p.In((ushort)1, (ushort)2, (ushort)3, (ushort)4, (ushort)5))
       return;
    

【问题讨论】:

    标签: c# .net extension-methods parameter-passing ushort


    【解决方案1】:

    好吧,你定义了一个泛型函数,所以你必须定义它必须处理的确切类型。因为如果你只给函数提供数字(1234 等)。它们可能只是任何东西shortushortinteger...

    所以你可以这样做:

    ushort p = 3;
    if (p.In<ushort>(1, 2, 3, 4, 5))
       return;
    

    或者像您在第二个示例中所做的那样,将每个参数转换为所需的类型:

    ushort p = 3;
    if (p.In((ushort)1, (ushort)2, (ushort)3, (ushort)4, (ushort)5))
       return;
    

    我个人更喜欢第一个案例。

    编辑

    为什么它在这种情况下有效:

    ushort p = 3;
    if (Extensions.In(p, 1, 2, 3, 4, 5))
       return;
    

    是因为您显式this(第一个参数)一样传递p,这是编译器的已知类型,所以它可以 推断它。

    1, 2, 3, 4, etc.默认类型int。所以当你打电话时

    p.In(1, 2, 3, 4, 5)
    

    T 被视为(或倾向于)像integer 值。由于编译器无法保证不会丢失任何数据(当您在整数上使用ushort 时),它会给出错误消息。它强制你显式定义一个更小的类型

    请注意:函数参数定义为T[],因此您传递整数(至少编译器是这样认为的)但假装它是ushort(因为您从p调用ext-method)。

    为了证明,尝试运行

    int p = 3;
    if (p.In(1, 2, 3, 4, 5))
       return;
    

    这很好用。

    【讨论】:

    • 第一个看起来更好,拍的。你知道我的第一个问题吗?
    • 一个更好的问题是为什么它不能根据来源推断类型是 ushort?
    • @juharr 完全正确,但是按照旧的方式,它推断!只有在扩展方法时才不会!
    • 我会guess 第一个参数(this 一个)将泛型类型固定为 ushort。之后,(1, 2, 3, 4, 5) 被视为整数,由于可能会丢失精度,因此无法自动转换为 ushort。我想我们需要 Eric Lippert 或 Jon Skeet 来回答这个问题。
    • @Martijn 那么为什么 Extension.In(p,1,2,3,4,5) 有效?很想看看 Eric 或 Jon 会说什么。
    【解决方案2】:

    为什么它适用于第二个例子,而不是第一个?

    首先,让我们弄清楚编译器推断T 是什么。有些参数是ushort,有些是intushort 隐式转换为int,而int 没有隐式转换为ushort,因此Tint

    这里的关键在 C# 4 规范的第 7.6.5.2 节(重点是我的):

    扩展方法 Ci.Mj 符合条件:

    • Ci 是一个非泛型、非嵌套类
    • Mj 的名字是标识符
    • 如上所示,当作为静态方法应用于参数时,Mj 是可访问和适用的
    • 存在从 expr 到 Mj 第一个参数的类型的隐式身份、引用或装箱转换

    存在从ushortint隐式 转换,但没有身份、引用或装箱 转换!

    所以,以下是合法的:

    Extensions.In<ushort>(p, 1, 2, 3, 4, 5);
    Extensions.In<int>(p, 1, 2, 3, 4, 5); // implicit conversion allowed
    Extensions.In(p, 1, 2, 3, 4, 5); // T is int
    p.In<ushort>(1, 2, 3, 4, 5);
    

    但以下不是:

    p.In<int>(1, 2, 3, 4, 5); // implicit conversion not allowed
    p.In(1, 2, 3, 4, 5); // T is int
    

    请注意,如果将In 定义为,则在没有泛型的情况下也会出现相同的错误

    public static bool In(this int source, params int[] list)
    {
        return list.Contains(source);
    }
    

    【讨论】:

    • 接受! An implicit identity, reference or boxing conversion exists from expr to the type of the first parameter of Mj. 给出了答案!虽然我相信 C# 可能会更聪明! :(
    猜你喜欢
    • 1970-01-01
    • 2012-12-20
    • 1970-01-01
    • 1970-01-01
    • 2020-03-23
    • 1970-01-01
    • 2012-04-21
    • 1970-01-01
    相关资源
    最近更新 更多