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

时间:2014-03-15 06:41:52

标签: c#

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)。有什么建议吗?

5 个答案:

答案 0 :(得分:4)

重载解析在编译时发生,在这种情况下,对T没有任何了解,因此不适用过载。

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

但当然可能会出现一些问题。例如,如果您将DateTime发送到方法,则应用程序将编译正常。但是,它会引发异常。

答案 1 :(得分:1)

在您的写入方法中,T是通用的,这意味着T可以是任何内容,但BinaryWriter.Write不会采用泛型过载。所以你不能这样做。

答案 2 :(得分:1)

你不能这样做。

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

答案 3 :(得分:1)

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

在构造函数中使用BinaryWriter初始化Stream,然后使用如下的反射:

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
}

答案 4 :(得分:-1)

  1. 使用Reflection会大大减慢方法调用的速度。它还将参数类型检查从编译时移动到运行时,这在大多数情况下是不合需要的。

  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;
    }
    
    // ...
    

    这个方法非常详细,但是它是唯一提供arument类型的编译时检查的方法,并且是选择重载和编译时最高效的方法。此外,这些方法可能会被内联。

    在这种情况下,我通常使用T4脚本,它基于Reflection生成如上所述的代码。创建一个TT文件,枚举Write的{​​{1}}重载,生成代码。