C # generics not recognizing type

I canโ€™t understand why the following code returns Cannot resolve method Write(T) - it seems to me unambiguous:

  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 general binary write method that can deal with vectors, for example, int[] , long[] or double[] .

+4
source share
4 answers

cdhowie has the correct explanation. Overload resolution occurs at compile time, in which case nothing is known about T , so overloading is not applicable.

With dynamic , overload resolution occurs at run time. Perhaps you can use:

 writer.Write((dynamic)v) 

It will be a little slow due to boxing and re-resolution of the congestion taking place.

Edit: If for some reason you do not have access to dynamic , you can get a similar behavior with an explicit reflection:

 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 do not know if it was faster or slower than dynamic .

In any case, if you accidentally use a type T (for example, DateTime ) that is not supported by BinaryWriter , everything will compile fine, and you will find your error only at runtime (when the code works). See jam40jeff's answer for a safer type, where you specify overloading yourself by passing the delegate instance to the method.

+3
source

What overload Write() for the call will be determined at compile time, and not at run time. BinaryWriter will require an overload of Write(object) (or a general overload of Write<T>(T) ) to allow the method to be called this way. This error (correctly) indicates that it does not.

You will need to write your own wrapper method that takes an object (or a typically typed argument) and checks its type to determine which BinaryWriter.Write() overload to call.

+10
source

I disagree that dynamic is the best way. The problem here is that you need to ensure that callers pass in a type T , which BinaryWriter.Write() can handle. Since there is no common class or interface that can guarantee this by restricting T , the best way to do this is to โ€œtransfer the dollarโ€ to the caller as follows:

 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 the following:

 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 is only a small set of known types, you can create "convenient 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 simple:

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

A bit more code, but much more security and speed in compilation mode.

+3
source

You can change it to:

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

if you want to save the array type as the value type of a number.

0
source

All Articles