Les génériques C # ne reconnaissent pas le type

Je n’arrive pas à comprendre pourquoi le code suivant renvoie une Cannot resolve method Write(T) – elle me semble sans ambiguïté:

  private static void WriteToDisk(ssortingng 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(); } } } 

J’aimerais définir une méthode d’écriture binary générique pouvant traiter des vecteurs, par exemple, int[] , long[] ou double[] .

Cdhowie a la bonne explication. La résolution de surcharge se produit au moment de la compilation, et dans ce cas, rien n’est connu à propos de T , donc aucune surcharge n’est applicable.

Avec dynamic résolution dynamic , la surcharge se produit à l’exécution. Peut-être que vous pouvez utiliser:

 writer.Write((dynamic)v) 

Ce sera un peu lent à cause de la boxe et de la résolution répétée de la surcharge prenant place à l’exécution.

Edit: Si pour une raison quelconque vous n’avez pas access à dynamic , vous pouvez obtenir un comportement similaire avec une reflection explicite:

 private static void WriteToDisk(ssortingng 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, }); } } } 

Je ne sais pas si c’est plus rapide ou plus lent que dynamic .

Dans les deux cas, si vous utilisez accidentellement un type T (tel que DateTime ) qui n’est pas pris en charge par BinaryWriter , tout se comstackra BinaryWriter et vous ne découvrirez votre erreur qu’au moment de l’exécution (lorsque le code est exécuté). Voir la réponse de jam40jeff pour une solution plus sécurisée par le type dans laquelle vous spécifiez vous-même la surcharge en transmettant une instance de délégué à la méthode.

La surcharge de Write() à appeler sera déterminée lors de la compilation, pas lors de l’exécution. BinaryWriter aurait besoin d’une surcharge Write(object) (ou d’une surcharge générique Write(T) ) pour autoriser l’appel de la méthode de cette façon. Cette erreur (correctement) indique qu’il n’a ni l’un ni l’autre.

Vous devrez écrire votre propre méthode d’encapsulation qui accepte un object (ou un argument de type générique) et inspecte son type pour déterminer le type de surcharge BinaryWriter.Write() à appeler.

Je ne suis pas d’accord pour dire que la dynamic est la meilleure voie à suivre. Le problème ici est que vous devez vous assurer que les appelants transmettent un type T que BinaryWriter.Write() peut gérer. Comme il n’y a pas de classe ou d’interface commune qui puisse garantir cela en contraignant T , la meilleure façon de le faire est de “transférer l’argent” à l’appelant comme suit:

 private static void WriteToDisk(ssortingng fileName, T[] vector, Action 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(); } } } 

Ceci s’appelle comme suit:

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

Bien sûr, s’il n’y a qu’un petit ensemble de types connus, vous pouvez créer des “méthodes pratiques” en tant que telles:

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

et maintenant vos appels sont simplement:

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

Un peu plus de code, mais beaucoup plus de sécurité et de rapidité au moment de la compilation.

Vous pouvez le changer pour:

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

si vous voulez conserver le type de tableau comme type de valeur numérique.