[英]C# generics not recognizing type
I can't figure out why the following code returns a Cannot resolve method Write(T)
- it seems unambiguous to me: 我无法弄清楚为什么以下代码返回一个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(); } } }
I would like to define a generic binary write method that can deal with vectors of, eg, int[]
, long[]
or double[]
. 我想定义一个通用的二进制写方法,它可以处理例如int[]
, long[]
或double[]
向量。
Which overload of Write()
to call will be determined at compile time, not at runtime. 调用Write()
哪个重载将在编译时确定,而不是在运行时确定。 BinaryWriter
would need a Write(object)
overload (or a Write<T>(T)
generic overload) to allow calling the method this way. BinaryWriter
需要Write(object)
重载(或Write<T>(T)
泛型重载)以允许以这种方式调用方法。 This error (correctly) indicates that it has neither. 此错误(正确)表示它既没有。
You will need to write your own wrapper method that accepts an object
(or a generically-typed argument) and inspects its type to determine which BinaryWriter.Write()
overload to call. 您需要编写自己的包装器方法,该方法接受一个object
(或一般类型的参数)并检查其类型以确定要调用的BinaryWriter.Write()
重载。
cdhowie has the correct explanation. cdhowie有正确的解释。 Overload resolution happens at compile-time, and in this case nothing is known about T
, so no overload is applicable. 重载解析在编译时发生,在这种情况下,对T
没有任何了解,因此不适用过载。
With dynamic
, overload resolution happens runtime. 通过dynamic
,重载解析发生在运行时。 Maybe you can use: 也许你可以使用:
writer.Write((dynamic)v)
It will be a bit slow because of boxing and repeated overload resolution taking place runtime. 由于拳击和重复的重载决策发生在运行时,它会有点慢。
Edit: If for some reason you don't have access to dynamic
, you can get a similar behavior with explicit reflection: 编辑:如果由于某种原因您无权访问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, });
}
}
}
I don't know if this is faster or slower than dynamic
. 我不知道这是否比dynamic
更快或更慢。
In either case, if you accidentally use a type T
(such as DateTime
) which is not supported by BinaryWriter
, everything will compile fine, and you will only discover your mistake at runtime (when the code runs). 在任何一种情况下,如果你不小心使用了BinaryWriter
不支持的类型T
(例如DateTime
),一切都会正常编译,你只会在运行时发现错误(代码运行时)。 See jam40jeff's answer for a more type-safe solution where you specify the overload yourself by passing in a delegate instance to the method. 请参阅jam40jeff的答案,了解更加类型安全的解决方案,您可以通过将委托实例传递给方法来自行指定过载。
I disagree that dynamic
is the best way to go. 我不同意dynamic
是最好的方式。 The problem here is that you need to guarantee that callers pass a type T
that BinaryWriter.Write()
can handle. 这里的问题是你需要保证调用者传递BinaryWriter.Write()
可以处理的类型T
Since there is no common class or interface that can guarantee this by constraining T
, the best way to do that is to "pass the buck" to the caller as follows: 由于没有可以通过约束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();
}
}
}
This is called as follows: 这称为如下:
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)
Of course, if there's only a small set of known types, you can create "convenience methods" as such: 当然,如果只有一小组已知类型,您可以创建“便利方法”:
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));
}
and now your calls are simply: 现在你的电话很简单:
WriteToDisk("filename", new int[0]);
WriteToDisk("filename", new string[0]);
A little more code, but a lot more compile-time type safety and speed. 多一点代码,但更多编译时类型的安全性和速度。
You can change it to: 您可以将其更改为:
private static void WriteToDisk<T>(string fileName, T[] vector) where T : struct, IComparable,IComparable<T>
if you want to keep type of array as number value type. 如果要将数组类型保持为数值类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.