2009-07-29 7 views
1

J'essaie de savoir pourquoi j'obtiens une exception de dépassement de pile. Je crée un jeu de cartes simple pour une tâche d'école et quand je clone les cartes pour les retourner, j'obtiens l'exception de dépassement de pile.Débordement de pile C#

donc je suis arrivé cette classe de carte:

public class Card : ICloneable 
{ 
    .... 

    #region ICloneable Members 

    public object Clone() 
    { 
     return this.Clone(); // <--- here is the error thrown when the first card is to be cloned 
    } 

    #endregion 
} 

et j'ai une classe appelée Hand qui clone alors les cartes:

internal class Hand 
{ 
     internal List<Card> GetCards() 
     { 
      return m_Cards.CloneList<Card>(); // m_Cards is a List with card objects 
     } 
} 

dernier, je suis arrivé une méthode d'extension pour la List:

L'erreur est renvoyée dans la classe de la carte (ICl)
public static List<T> CloneList<T>(this List<T> listToClone) where T : ICloneable 
    { 
     return listToClone.Select(item => (T)item.Clone()).ToList(); 
    } 

méthode onable),

Une exception non gérée du type 'System.StackOverflowException' a eu lieu dans CardLibrary.dll

+2

Est-ce que les cartes doivent être mutable dire qu'ils n'ont l'état qui peut changer? Sinon, vous pourriez simplement avoir un ensemble de cartes immuables que vous pourriez réutiliser dans différentes collections. Aucun clonage nécessaire. – pjp

+0

S'il vous plaît voir aussi cette discussion concernant ICloneable: http://stackoverflow.com/questions/699210/why-should-i-implement-icloneable-in-c – peterchen

+0

Après avoir lu le titre de cette question, je pensais que cela appartient à méta. .. ;-) – EricSchaefer

Répondre

22

Vous vous appeler:

public object Clone() 
{ 
    return this.Clone(); 
} 

Il en résulte une récursion infinie.

Votre méthode clone() doit copier toutes les propriétés/champs à un nouvel objet:

public object Clone() 
{ 
    Card newCard = new Card(); 

    newCard.X = this.X; 
    // ... 

    return newCard; 
} 

ou vous pouvez utiliser MemberwiseClone()

public object Clone() 
{ 
    return MemberwiseClone(); 
} 

Mais cela vous donne moins de contrôle sur le clonage processus.

+1

+1, bonne réponse. Chaque fois que vous utilisez 'MemberwiseClone()', n'oubliez pas qu'il ne crée qu'une copie superficielle, c'est-à-dire si un champ de classe est un type de référence, la référence est copiée, mais pas l'objet référencé. –

0

J'ai tendance à utiliser MemberwiseClone() pour les données simples, puis mis en œuvre ICloneable throghout la hiérarchie des éléments que j'ai besoin pour cloner, donc:

public class CRMLazyLoadPrefs : ICloneable 
{ 
    public bool Core { get; set; } 
    public bool Events { get; set; }  
    public bool SubCategories { get; set; } 
    public OrganisationLazyLoadPrefs { get; set; } 

    public object Clone() 
    { 
     CRMLazyLoadPrefs _prefs = new CRMLazyLoadPrefs(); 
     // firstly, shallow copy the booleans 
     _prefs = (CRMLazyLoadPrefs)this.MemberwiseClone(); 
     // then deep copy the other bits 
     _prefs.Organisation = (OrganisationLazyLoadPrefs)this.Organisation.Clone(); 
    } 
} 

Où OrganisationLazyLoadPrefs met également en œuvre et ICloneable ainsi de suite et ainsi de suite tout au long de la hiérarchie.

Hope this helps, Cheers, Terry

+0

juste vu ce commentaire de @peterchen, cependant, devra examiner cela plus en détail - désireux de suivre les meilleures pratiques autant que possible. –

Questions connexes