【问题标题】:Generic method can't call correct overload泛型方法不能调用正确的重载
【发布时间】:2011-08-22 21:25:33
【问题描述】:

注意:我使用的是 Mono 环境,如果这会有所不同的话。

我正在编写一些测试,为此我提供了以下通用方法:

static MemoryStream writeValue<T>(T inVal)
{
  MemoryStream ms = new MemoryStream();
  BinaryWriter bw = new BinaryWriter(ms);
  encode_any(bw, inVal);
  return ms;
}

这个想法是这将调用我的encode_any 重载之一,它委托给特定类型的方法:

public static void encode_any(BinaryWriter writer, Int32 val) { encode_int32(writer, val); }
public static void encode_any(BinaryWriter writer, Int64 val) { encode_int64(writer, val); }
public static void encode_any(BinaryWriter writer, Float val) { encode_float(writer, val); }
...etc...
public static void encode_any(BinaryWriter writer, bool val) { encode_bool(writer, val); }

我想这样做的原因是,我可以在每种情况下调用正确的实现,而无需多个版本的“writeValue”,也无需在选择调用哪个 encode_ 函数之前检查每个项目的运行时类型。

但是,编译器似乎正在尝试解决 writeValue 的重载,但不知道 T 将是什么类型,所以我收到此错误:

错误 CS1502:“BinarySerialiser.encode_any(System.IO.BinaryWriter, bool)”的最佳重载方法匹配有一些无效参数 错误 CS1503:参数“#2”无法将“T”表达式转换为“bool”类型

我注意到这不是专门针对 bool 的——如果我重新排列我的 encode_any 函数的顺序,它总是会尝试使用最后一个。也许它只是尝试每一个,然后只在用完替代品时才发出错误。

这种代码在 C++ 下可以正常工作,其中 writeValue 仅在 T 已知时编译,但这里似乎不是这种情况,我怀疑这是因为 C# 在运行时处理泛型类型。

我可以改变我的方法来完成这项工作吗?如果可以,如何?

【问题讨论】:

    标签: c# .net generics mono


    【解决方案1】:

    这不是 C++ 而是 C#。这意味着,您拥有的代码不起作用,因为在 C# 的泛型类中,您可以访问泛型类型参数的所有已知成员。哪些成员是已知的,完全取决于您对泛型类型参数施加的约束。 IIRC,在 C++ 中有点不同。
    无论如何,在您的情况下,T 没有任何限制,因此编译器对该通用参数一无所知。但是,没有任何限制可以让你做你想做的事。
    如果您使用的是 .NET 4.0,则可以使用新的 dynamic 关键字:

    static MemoryStream writeValue<T>(T inVal)
    {
      MemoryStream ms = new MemoryStream();
      BinaryWriter bw = new BinaryWriter(ms);
      dynamic dynamicValue = inVal;
      encode_any(bw, dynamicValue);
      return ms;
    }
    

    因为你用的是 Mono,我觉得你不能用这个,因为 Mono 还没有实现这个关键字。
    看起来 Mono 已经实现了 DLR,请参见下面 paolo 的链接。

    【讨论】:

    • +1 我在写同样的东西,但你更快...顺便说一句,我认为 mono does have dynamic 使用 C# 4 配置文件时
    • “这不是 C++ 而是 C#。这意味着,你的代码不起作用,因为 C# 中的泛型是编译时特性。” C++ 中的泛型是一种编译时特性。所以你的答案的第一点没有意义。
    • 是的,这是有道理的。不幸的是,我没有可用的动态关键字,所以看起来我必须走复制和粘贴路线!
    【解决方案2】:

    您的问题是重载解析是在编译时完成的,而不是运行时 - 在这种情况下,在以下行:

    encode_any(bw, inVal);
    

    inVal 除了inVal 是(或可以装箱)对象之外没有其他类型约束,因此只有接受对象的重载才会被考虑用于重载决议。

    另见Generic overload resolution

    我的方法可能是创建一个encode_any 重载,它接受一个对象并确定在运行时调用哪个方法。

    【讨论】:

    • 从 C++ 经验来看,问题不是编译时问题(因为这在 C++ 中工作得很好,它在编译时完成所有工作),但显然它试图为所有类型编译单个版本的 writeValue,而不是为每种类型编译单独的版本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多