繁体   English   中英

C#泛型无法识别类型

[英]C# generics not recognizing type

我无法弄清楚为什么以下代码返回一个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[]向量。

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

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

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更快或更慢。

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

我不同意dynamic是最好的方式。 这里的问题是你需要保证调用者传递BinaryWriter.Write()可以处理的类型T 由于没有可以通过约束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]);

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

您可以将其更改为:

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM