4

我不知道为什么下面的代码返回 a Cannot resolve method Write(T)- 这对我来说似乎很明确:

    private static void WriteToDisk<T>(string fileName, T[] vector)
    {
        using (var stream = new FileStream(fileName, FileMode.Create))
        {
            using (var writer = new BinaryWriter(stream))
            {
               foreach(T v in vector) writer.Write(v);
                writer.Close();
            }
        }
    }

我想定义一个通用的二进制写入方法,可以处理向量,例如int[]long[]double[]

4

4 回答 4

10

调用的哪个重载Write()将在编译时确定,而不是在运行时确定。 BinaryWriter需要Write(object)重载(或Write<T>(T)泛型重载)才能允许以这种方式调用该方法。此错误(正确)表明它两者都没有。

您将需要编写自己的包装器方法,该方法接受一个object(或通用类型的参数)并检查其类型以确定BinaryWriter.Write()要调用的重载。

于 2013-01-02T22:39:29.343 回答
3

cdhowie 有正确的解释。重载解决发生在编译时,在这种情况下,对 没有任何了解T,因此不适用重载。

使用dynamic,重载决议发生在运行时。也许你可以使用:

writer.Write((dynamic)v)

由于在运行时发生装箱和重复的重载解析,它会有点慢。

编辑:如果由于某种原因您无权访问dynamic,则可以通过显式反射获得类似的行为:

private static void WriteToDisk<T>(string fileName, T[] vector)
{
    var correctMethod = typeof(BinaryWriter).GetMethod("Write", new[] { typeof(T), });
    if (correctMethod == null)
        throw new ArgumentException("No suitable overload found for type " + typeof(T), "T");
    using (var stream = new FileStream(fileName, FileMode.Create))
    {
        using (var writer = new BinaryWriter(stream))
        {
           foreach(var v in vector)
               correctMethod.Invoke(writer, new object[] { v, });
        }
    }
}

我不知道这是否比dynamic.

在任何一种情况下,如果您不小心使用了不支持的类型T(例如) ,一切都会正常编译,并且您只会在运行时(代码运行时)发现错误。有关更类型安全的解决方案,请参阅 jam40jeff 的答案,您可以通过将委托实例传递给方法来自己指定重载。DateTimeBinaryWriter

于 2013-01-02T22:46:55.787 回答
3

我不同意这dynamic是最好的方法。这里的问题是你需要保证调用者传递一个T可以BinaryWriter.Write()处理的类型。由于没有通用类或接口可以通过约束来保证这一点T,因此最好的方法是将责任“转嫁”给调用者,如下所示:

private static void WriteToDisk<T>(string fileName, T[] vector, Action<BinaryWriter, T> callWrite)
{
    using (var stream = new FileStream(fileName, FileMode.Create))
    {
        using (var writer = new BinaryWriter(stream))
        {
            foreach (T v in vector)
                callWrite(writer, v);
            writer.Close();
        }
    }
}

这被称为如下:

WriteToDisk("filename", new int[0], (w, o) => w.Write(o)); // compiles
WriteToDisk("filename", new string[0], (w, o) => w.Write(o)); // compiles
WriteToDisk("filename", new DateTime[0], (w, o) => w.Write(o)); // doesn't compile (as desired)

当然,如果只有一小部分已知类型,您可以这样创建“便捷方法”:

private static void WriteToDisk(string fileName, int[] vector)
{
    WriteToDisk(fileName, vector, (w, o) => w.Write(o));
}

private static void WriteToDisk(string fileName, string[] vector)
{
    WriteToDisk(fileName, vector, (w, o) => w.Write(o));
}

现在你的电话很简单:

WriteToDisk("filename", new int[0]);
WriteToDisk("filename", new string[0]);

更多的代码,但更多的编译时类型安全和速度。

于 2013-01-03T04:58:51.547 回答
0

您可以将其更改为:

private static void WriteToDisk<T>(string fileName, T[] vector) where T : struct, IComparable,IComparable<T>

如果要将数组类型保留为数值类型。

于 2013-01-02T22:46:51.937 回答