在泛型方法中调用重载方法

7
class Test
{
    public BinaryWriter Content { get; private set; }
    public Test Write<T> (T data)
    {
        Content.Write(data);
        return this;
    }
}

它无法编译。

1. The best overloaded method match for 'System.IO.BinaryWriter.Write(bool)' has some invalid arguments
2. Argument 1: cannot convert from 'T' to 'bool'

看起来 Test.Write 总是试图调用 BinaryWriter.Write(bool)。有什么建议吗?


可能是C#无法从泛型方法调用重载的非泛型方法的重复问题。 - safetyOtter
5个回答

6

重载决策发生在编译时,在这种情况下,关于T没有任何信息,因此没有任何重载是适用的。

   class Test
    {
        public BinaryWriter Content { get; private set; }
        public Test Write<T>(T data)
        {
            Content.Write((dynamic)data);
            return this;
        }
    }

当然,这可能会带来一些问题。例如,如果将DateTime发送到方法中,应用程序将编译成功,但是它将抛出异常。


4
也许这种方法能够解决问题,但是这种方式很危险且容易出现异常情况。 - Selman Genç
实际上,在这种情况下,它不需要是通用方法。 - Laie

2

这是可能的,但不适用于通用约束。您可以尝试使用反射并根据T类型获取相应重载版本的Write方法。

在构造函数中,使用Stream初始化您的BinaryWriter,然后像下面这样使用反射:

class Test
{
    public BinaryWriter Content { get; private set; }

    public Test(Stream stream)
    {
        Content = new BinaryWriter(stream);
    }

    public Test Write<T>(T data)
    {

        var method = typeof (BinaryWriter).GetMethod("Write", new[] {data.GetType()});
        if (method != null)
        {
            method.Invoke(Content, new object[] { data });
        }
        // here you might want to throw an exception if method is not found

        return this;
    }
}

这是一个测试程序:

Test writer;
using (var fs = new FileStream("sample.txt", FileMode.Open))
{
     writer = new Test(fs);
     writer = writer.Write(232323);
     writer = writer.Write(true);
     writer = writer.Write(12);
}

using (var fs = File.Open("sample.txt", FileMode.Open))
{
    var reader = new BinaryReader(fs);
    Console.WriteLine(reader.ReadInt32());  // 232323
    Console.WriteLine(reader.ReadBoolean()); // true
    Console.WriteLine(reader.ReadByte());    // 12
}

1
  1. 使用反射会显著降低方法调用的速度。它还将参数类型检查从编译时移动到运行时,这在大多数情况下是不可取的。

  2. 在这种情况下使用动态调用只是之前方法的花哨和稍微优化版本,具有相同的缺点。

  3. 正确的方法是复制所有重载:

    public Test Write (bool data)
    {
        Content.Write(data);
        return this;
    }
    
    public Test Write (byte data)
    {
        Content.Write(data);
        return this;
    }
    
    public Test Write (byte[] data)
    {
        Content.Write(data);
        return this;
    }
    
    public Test Write (char data)
    {
        Content.Write(data);
        return this;
    }
    
    public Test Write (char[] data)
    {
        Content.Write(data);
        return this;
    }
    
    // ...
    

    这个方法非常冗长,但它是唯一提供了编译时参数类型检查并且选择了最佳重载以及编译时间最优的方法。此外,这些方法很可能会被内联。

    在这种情况下,我通常使用一个 T4 脚本,该脚本基于反射生成类似上面的代码。创建 TT 文件,枚举 BinaryWriterWrite 重载,生成代码。


1
最令人烦恼的是,我永远看不到“-1”的解释。 - Athari

0
在你的写入方法中,T 是泛型,这意味着 T 可以是任何类型,但是 BinaryWriter.Write 没有泛型重载。所以你不能这样做。

0

你不能这样做。

由于编译时无法确定 T 的实际类型,编译器无法找到适当的 Write 重载,并尝试调用找到的第一个。没有任何重载可以使用任何类型的 T 进行调用(例如,Write(object))。


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