c#泛型不能识别类型
本文关键字:类型 识别 不能 泛型 | 更新日期: 2023-09-27 17:50:23
我不明白为什么下面的代码返回一个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()
重载。
chowie有正确的解释。重载解析发生在编译时,在这种情况下,对T
一无所知,因此不适用重载。
对于dynamic
,重载解析发生在运行时。也许你可以用:
writer.Write((dynamic)v)
它会有点慢,因为在运行时发生了装箱和重复的重载解析。
Edit:如果由于某种原因您没有访问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>