通用方法无法调用正确的重载版本。

6

注意:我使用的是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的类型将是什么,因此我会得到以下错误:
error CS1502:'BinarySerialiser.encode_any(System.IO.BinaryWriter, bool)'的最佳重载方法匹配有一些无效的参数 error CS1503:参数'#2'不能将'T'表达式转换为类型'bool'
我注意到这并不特别与布尔值有关,如果我重新排列我的encode_any函数的顺序,它总是尝试使用最后一个。也许它只是尝试每个函数,然后在用完备选项后才发出错误。
这种代码在C ++下工作得很好,其中writeValue仅在已知T时编译,但在这里似乎不是这种情况,我怀疑这是因为C#在运行时处理通用类型。
我能改变我的方法使其工作吗?如果可以,那该怎么做?
2个回答

8
这不是C++,而是C#。这意味着你的代码无法工作,因为在C#的泛型类中,你可以访问所有已知的泛型类型参数成员。哪些成员是已知的完全取决于你对泛型类型参数设置的约束条件。据我所知,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
+1 我也在写同样的东西,但你更快... 顺便说一下,我认为 mono 在使用 C# 4 配置文件时确实具有动态功能 - Paolo Falabella
1
这不是C++而是C#。这意味着,你所拥有的代码无法工作,因为C#中的泛型是编译时特性。C++中的泛型也是编译时特性。因此,你的第一部分回答没有意义。 - Kylotan
是的,那很有道理。不幸的是,我没有可用的动态关键字,所以看起来我必须走复制粘贴的路线! - Kylotan

1
你的问题在于重载决策是在编译时而不是运行时进行的 - 在这种情况下是在以下行上:
encode_any(bw, inVal);

inVal没有类型约束,除了inVal是(或可以装箱为)对象之外,因此只考虑接受对象的重载来进行重载决策。

另请参见通用重载决策

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


1
从C++的经验来看,问题不在于编译时间(因为在C++中这个过程完全正常),而在于它试图为所有类型编译一个单一版本的writeValue,而不是为每种类型分别编译不同的版本。 - Kylotan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接