2009-08-27 13 views
18

J'ai une classe MyClass, et je voudrais remplacer la méthode ToString() des instances de la liste:Redéfinition ToString() de la liste <MyClass>

class MyClass 
{ 
    public string Property1 { get; set; } 
    public int Property2 { get; set; } 
    /* ... */ 
    public override string ToString() 
    { 
     return Property1.ToString() + "-" + Property2.ToString(); 
    } 
} 

Je voudrais avoir les éléments suivants:

var list = new List<MyClass> 
      { 
       new MyClass { Property1 = "A", Property2 = 1 }, 
       new MyClass { Property1 = "Z", Property2 = 2 }, 
      }; 

Console.WriteLine(list.ToString()); /* prints: A-1,Z-2 */ 

Est-il possible de le faire? Ou je devrais sous-classe Liste < MyClass> pour remplacer la méthode ToString() dans ma sous-classe? Puis-je résoudre ce problème en utilisant des méthodes d'extension (ie, est-il possible de surcharger une méthode avec une méthode d'extension)?

Merci!

+0

Pour information: J'essayais de faire quelque chose en rapport avec NHibernate, et le mappage des collections dans une chaîne sérialisée qui correspondrait à une seule colonne. Cependant j'ai trouvé une autre façon de le faire, en implémentant mon propre IUserType, et mon implémentation construit la chaîne comme j'en ai besoin! Merci à tous ceux qui ont répondu quand même! –

Répondre

21

Vous aurez besoin de sous-classe pour remplacer toute méthode. Le point des génériques est de dire que vous voulez le même comportement quel que soit le type de T. Si vous voulez un comportement différent pour un type spécifique de T alors vous rompez ce contrat et devrez écrire votre propre classe:

public class MyTypeList : List<MyClass> 
{ 
    public override string ToString() 
    { 
     return ... 
    } 
} 

Modifié ajouter:

non, vous ne pouvez pas passer outre une méthode en créant une extension, mais vous pouvez créer une nouvelle méthode avec une signature différente qui est spécifique à ce type de liste:

public static string ExtendedToString(this List<MyClass> list) 
{ 
    return .... 
} 

méthode utilisée avec

Je pense toujours que vous êtes mieux subclassing mais ...

+1

Il y a si peu de code pour la nouvelle classe de liste, donc je l'inclue dans le même fichier de code que la classe 'MyClass'. Donc ce n'est pas vraiment un effort supplémentaire à faire, même si cela semble compliqué de créer une nouvelle classe, ce n'est pas parce que la plupart des fonctionnalités sont héritées de la classe 'List' ... – awe

+0

** A propos de l'extension méthode: ** Je suis d'accord que dans ce cas, vous devriez aller avec le sous-classement, parce que la méthode 'ToString' est logiquement ce que vous voulez, et' List' n'a pas l'implémentation par défaut très utile de celui-ci. Extension ajouterait une nouvelle méthode et laisserait la méthode 'ToString' là aussi inutile qu'elle l'a toujours été pour la classe générique' List'. – awe

0

Vous devez créer votre propre classe personnalisée qui hérite de la collection et la overwride ToString() de cette classe en particulier.

2

Si votre méthode doit être nommée ToString, vous devrez dériver une classe de List. Vous pouvez faire un générique:

static class MyList<T> : List<T> 
{ 
    public override string ToString() 
    { 
     // ... 
    } 
} 

Dans ce cas, vous devez utiliser MyList au lieu de List tout au long de votre demande si vous souhaitez que votre conversion personnalisée.

Cependant, si vous pouvez choisir un autre nom pour votre méthode, vous pouvez utiliser des méthodes d'extension et obtenir le même effet, avec presque aucune modification à votre code:

Vous pouvez utiliser des méthodes d'extension pour rendre plus générique :

static class ListExtension 
{ 
    public static void ConvertToString<T>(this IEnumerable<T> items) 
    { 
     // ... 
    } 
} 

Vous pouvez l'utiliser sur une instance de IEnumerable<T> comme si elle était une méthode ordinaire:

List<MyClass> list = new List<MyClass> { ... }; 
Console.WriteLine(list.ConvertToString()); 

int[] array_of_ints = {1,2,3,4,5}; 
Console.WriteLine(array_of_ints.ConvertToString()); 
0

non pas son p ossible. ToString of TList vous donnera la représentation sous forme de chaîne de l'objet liste.

Vos options sont:

  • Derive de TList et remplacer la méthode ToString() comme vous l'avez mentionné.(dans cet exemple, je ne dirais pas que cela vaut la peine de le faire)
  • Créer une méthode d'assistance qui convertit une liste TList en une chaîne délimitée par des virgules, par ex. méthode d'extension (probablement la meilleure suggestion)
  • Utilisez une instruction foreach à l'étape Console.WriteLine.

Espérons que ça aide!

21

Peut-être un peu hors sujet, mais j'utilise une méthode d'extension ToDelimitedString qui fonctionne pour tout IEnumerable<T>. Vous pouvez (en option) spécifier le séparateur à utiliser et un délégué pour effectuer une conversion de chaîne personnalisée pour chaque élément:

// if you've already overridden ToString in your MyClass object... 
Console.WriteLine(list.ToDelimitedString()); 
// if you don't have a custom ToString method in your MyClass object... 
Console.WriteLine(list.ToDelimitedString(x => x.Property1 + "-" + x.Property2)); 

// ... 

public static class MyExtensionMethods 
{ 
    public static string ToDelimitedString<T>(this IEnumerable<T> source) 
    { 
     return source.ToDelimitedString(x => x.ToString(), 
      CultureInfo.CurrentCulture.TextInfo.ListSeparator); 
    } 

    public static string ToDelimitedString<T>(
     this IEnumerable<T> source, Func<T, string> converter) 
    { 
     return source.ToDelimitedString(converter, 
      CultureInfo.CurrentCulture.TextInfo.ListSeparator); 
    } 

    public static string ToDelimitedString<T>(
     this IEnumerable<T> source, string separator) 
    { 
     return source.ToDelimitedString(x => x.ToString(), separator); 
    } 

    public static string ToDelimitedString<T>(this IEnumerable<T> source, 
     Func<T, string> converter, string separator) 
    { 
     return string.Join(separator, source.Select(converter).ToArray()); 
    } 
} 
+0

Bonne suggestion en général: j'utilise moi-même une telle méthode d'extension. Selon le contexte exact de la question d'origine, cette réponse pourrait ou non être valide ici. – peSHIr

+0

Ce sont des méthodes d'extension très pratiques, merci! A m'a aidé charges à l'intérieur d'une fonction en utilisant un IList de types enum anonymes pour les convertir en une liste séparée par des virgules, juste utilisé (x => ((court) Convert.ChangeType (x, TypeCode.Int16)) comme paramètre de conversion. Luke –

+0

Comme danrichardson commentaire, merci pour l'entrée c'est très utile! –

0

Selon la raison exacte que vous avez de vouloir remplacer List<T>.ToString() retourner quelque chose de spécifique, il pourrait être à portée de main pour voir les implémentations personnalisées TypeConverter.

Si vous voulez simplement un List<T> de T spécifique pour se montrer d'une certaine manière comme string dans des endroits où TypeConverters sont utilisés, comme dans le débogueur ou dans string.Format("List: {0}", listVariable) situations de type, cela pourrait être suffisant.

Vous avez peut-être vu le résultat de ToString() affiché quelque part et que vous vouliez changer, sans connaître l'existence de TypeConverter et les emplacements où ils sont utilisés. Je crois que many/most/all (pas sûr de quoi?) Des TypeConverters par défaut dans .NET Framework utilisent simplement ToString() lors de la conversion de tout type pour lequel ils sont définis en string.

2

Vous pouvez réellement utiliser un astuce Unicode pour vous permettre de définir une autre méthode ToString directement par rapport à votre liste générique.

Si vous activez la saisie de caractères hexadécimal dans Visual Studio, vous pouvez alors créer des personnages invisibles en maintenant la touche Alt, puis en appuyant sur les éléments suivants sur votre pavé numérique + FFF 9 (libérer maintenant Alt)

Nous pouvons donc créer la fonction suivante avec un caractère invisible placé à côté de son nom ... (oui je sais son code VB, mais le concept sera encore travailler travail pour C#)

<Extension()> _ 
Public Function ToString(ByVal source As Generic.List(Of Char)) As String 
    Return String.Join(separator:="", values:=source.ToArray) 
End Function 

maintenant en studio visuel, lorsque vous accédez à IntelliSense contre votre liste, vous serez en mesure de choisir entre la ToString standard ou votre fonction personnalisée.


Pour activer la saisie de caractères hexagonale dans le studio visuel vous devrez peut-être modifier votre registre

ouvert HKEY_CURRENT_USER \ Control Panel \ Méthode d'entrée et créez un REG_SZ appelé EnableHexNumpad réglez ce paramètre sur 1

Vous Vous devez également désactiver les raccourcis & pour les menus Fichier, Edition, Déboguer, Données, Dans Visual Studio, ouvrez le menu Outils, sélectionnez Personnaliser, puis ouvrez l'onglet Commandes et utilisez le bouton Modifier la sélection pour tout élément de menu qui utilise soit de l'ABCDEF caractérise pour son raccourci, en supprimant le &

Sinon, vous finirez par ouvrir les menus contextuels au lieu de taper des caractères hexadécimaux.

+0

c'est dégoûtant et votre réponse devrait être supprimée pour toute l'éternité .... +1 –

+1

Idk si cela fonctionne, mais semble ingénieux et m'a donné une bonne rire! +1 –

Questions connexes