Perché / quando sarebbe opportuno sovrascrivere ToString?


103

Sto studiando C # e mi chiedo quale ToStringpotrebbe essere il punto e il vantaggio dell'override , come mostrato nell'esempio seguente.

Potrebbe essere fatto in qualche modo più semplice, usando un metodo comune senza override?

public string GetToStringItemsHeadings
{
    get { return string.Format("{0,-20} {1, -20}", "Office Email", "Private Email"); }
}


public override string ToString()
{
    string strOut = string.Format("{0,-20} {1, -20}", m_work, m_personal);
    return strOut;
}

4
Dipende se si desidera effettivamente utilizzarlo per visualizzare l'oggetto nell'interfaccia utente ovunque, altrimenti di solito è solo per il debug: vedrai l'output ToString nella finestra di controllo di VS. (Ma puoi anche ottenerlo con gli attributi sulla classe.) Dato che hai intestazioni e output, sembra che questo programma lo stia usando per scaricare l'oggetto usando Console.WriteLine(obj.GetToStringItemsHeadings); Console.WriteLine(obj);o simili.
Rup

2
Non capisco davvero la domanda. Può essere fatto diversamente? Sì. Ma perché vuoi farlo in modo diverso.
Konrad Rudolph

5
Vorrei davvero saltare GetToStringil nome della proprietà ... Quindi, ad esempioConsole.WriteLine(obj.ItemHeadings)
otterresti

e modificare la proprietà ItemHeadings in modo che sia statica poiché non è necessario alcun "this".
eFloh

Risposte:


127
  • Hai bisogno di sovrascrivere ToString? No.

  • Puoi ottenere una rappresentazione di stringa del tuo oggetto in un altro modo? Sì.

Ma usando ToStringstai usando un metodo che è comune a tutti gli oggetti e quindi altre classi conoscono questo metodo. Ad esempio, ogni volta che il framework .NET vuole convertire un oggetto in una rappresentazione di stringa, ToStringè un ottimo candidato (ce ne sono altri, se si desidera fornire opzioni di formattazione più elaborate).

concretamente,

Console.WriteLine(yourObject);

invocerebbe yourObject.ToString().


13
Sì. Anche questo è molto utile nello sviluppo MVC o ASP.Net dove @yourObjecte <%=yourObject%>saranno "ToString-ed".
Ben Lesh

4
Inoltre, quando si popola una casella combinata, ToString è la chiamata predefinita per ottenere il testo dell'elemento
Davi Fiamenghi

3
Attenti a tale pratica. Storia vera: uno studente ha sovrascritto ToString con un metodo che oltre a restituire una stringa, ha cambiato i dati. Stava eseguendo il debug del programma ma mentre il programma si trovava su un punto di interruzione il valore continuava a cambiare. Apparentemente - ogni volta che controllava il valore ToString veniva eseguito - quindi il valore cambiava anche se il programma non era in esecuzione.
JNF

3
@JNF Cos'è "tale pratica"? ToStringnon dovrebbe effettivamente cambiare lo stato di un oggetto. Ma questo non è quello che ho sostenuto.
Konrad Rudolph

8
@JNF Non lo accetto. ToStringè pensato per essere sovrascritto. Periodo. Mettere un avvertimento su questa affermazione non è produttivo. Se sbagli, è colpa tua. In effetti, il tuo studente ha violato il punto 4 nell'elenco ufficiale delle linee guida per l'override ToStringche è stato pubblicato nella risposta di David Anderson.
Konrad Rudolph

129

Ti darò solo la risposta direttamente dalle Linee guida per la progettazione del framework della serie di sviluppo .NET.

EVITARE di lanciare eccezioni daToString

CONSIDERARE di restituire una stringa univoca associata all'istanza.

CONSIDERARE di avere l'output di ToStringessere un input valido per qualsiasi metodo di analisi su questo tipo.

ASSICURARSI che ToStringnon abbia effetti collaterali osservabili.

DO rapporto le informazioni sensibili alla sicurezza attraverso un override ToStringsolo dopo chiedendo un'autorizzazione appropriata. Se la richiesta di autorizzazione non riesce, restituisci una stringa che esclude le informazioni sensibili alla sicurezza.

Il Object.ToStringmetodo deve essere utilizzato per scopi generali di visualizzazione e debug. L'implementazione predefinita fornisce semplicemente il nome del tipo di oggetto. L'implementazione predefinita non è molto utile e si consiglia di sovrascrivere il metodo.

FARE override ToStringogni volta che può essere restituita una stringa leggibile dall'uomo interessante. L'implementazione predefinita non è molto utile e un'implementazione personalizzata può quasi sempre fornire più valore.

FARE preferisce un nome nel corso di un unico ID, ma non leggibile.

Vale anche la pena menzionare come Chris Sells spiega anche nelle linee guida che ToStringè spesso pericoloso per le interfacce utente. In genere la mia regola pratica è esporre una proprietà che verrebbe utilizzata per associare le informazioni all'interfaccia utente e lasciare l' ToStringoverride per la visualizzazione delle informazioni diagnostiche allo sviluppatore. Puoi anche decorare il tuo tipo con DebuggerDisplayAttribute.

PROVA a mantenere la stringa restituita da ToStringbreve. Il debugger utilizza ToStringper ottenere una rappresentazione testuale di un oggetto da mostrare allo sviluppatore. Se la stringa è più lunga di quanto il debugger possa visualizzare, l'esperienza di debug è ostacolata.

Eseguire la formattazione della stringa in base alle impostazioni cultura del thread corrente quando si restituiscono informazioni dipendenti dalle impostazioni cultura.

DO fornire sovraccarico ToString(string format)o attuare IFormattable, se il ritorno stringa dal ToStringè sensibile-coltura o ci sono vari modi per formattare la stringa. Ad esempio, DateTimefornisce il sovraccarico e implementa IFormattable.

NON restituire una stringa vuota o null daToString

Lo giuro su queste linee guida e dovresti farlo. Non posso dirti come il mio codice sia migliorato solo con questa linea guida per ToString. La stessa cosa vale per cose come IEquatable(Of T)e IComparable(Of T). Queste cose rendono il tuo codice molto funzionale e non ti pentirai di aver dedicato del tempo extra per implementarlo.

Personalmente, non ho mai usato ToString molto per le interfacce utente, ho sempre esposto una proprietà o un metodo di qualche tipo. La maggior parte delle volte dovresti usare ToStringper il debug e per scopi di sviluppo. Usalo per visualizzare importanti informazioni diagnostiche.


6
Bella risposta, sono queste le linee guida a cui fai riferimento msdn.microsoft.com/en-us/library/ms229042.aspx ?
Jodrell

2
@Jodrell Credo che sia tratto da Framework Design Guidelines
Jim Schubert,

6
È necessaria una citazione migliore.
Ben Voigt

13
Non sapevo che SO si stesse trasformando in Wikipedia.
David Anderson

14
Non lo è, ma quando si citano le linee guida, fornire la fonte è un vantaggio indiscutibile.
Falanwe

39

Override ToString() consente di fornire un'utile rappresentazione di stringa leggibile dall'uomo di una classe.

Ciò significa che l'output può rivelare informazioni utili sulla tua classe. Ad esempio, se avessi una classe Person potresti scegliere di avere ilToString() output dell'id della persona, del suo nome, del suo cognome, ecc. Questo è estremamente utile durante il debug o il log.

Per quanto riguarda il tuo esempio - è difficile dire se il tuo override è utile senza sapere cosa sia questa classe - ma l'implementazione stessa è ok.


13

È sempre appropriato, ma considera attentamente le intenzioni dietro ciò che stai mostrando

Una domanda migliore sarebbe chiedere:

Perché si dovrebbe sovrascrivere ToString ()?

ToString () è la finestra sullo stato di un oggetto. Enfasi sullo stato come requisito. Linguaggi fortemente OOP come Java / C # abusano del modello OOP incapsulando tutto in una classe. Immagina di scrivere codice in un linguaggio che non segue il forte modello OOP; considera se useresti una classe o una funzione. Se vuoi usarlo come una funzione (cioè verbo, azione) e lo stato interno viene mantenuto solo temporaneamente tra input / output, ToString () non aggiunge valore.

Come altri hanno già detto, è importante considerare ciò che produci con ToString () perché potrebbe essere usato dal debugger o da altri sistemi.

Mi piace immaginare il metodo ToString come il parametro --help di un oggetto. Dovrebbe essere breve, leggibile, ovvio e facile da visualizzare. Dovrebbe mostrare ciò che l'oggetto non è ciò che fa . Con tutto ciò in mente, consideriamo ...

Caso d'uso - Analisi di un pacchetto TCP:

Non un'acquisizione di rete solo a livello di applicazione, ma qualcosa con più carne come un'acquisizione pcap.

Vuoi sovraccaricare ToString () solo per il livello TCP in modo da poter stampare i dati sulla console. Cosa includerebbe? Potresti impazzire e analizzare tutti i dettagli del TCP (cioè TCP è complesso) ...

Che include:

  • Porta di origine
  • Porto di destinazione
  • Sequenza di numeri
  • Numero di riconoscimento
  • Offset dei dati
  • bandiere
  • Finestra Offset
  • checksum
  • Puntatore urgente
  • Opzioni (non ci andrò nemmeno )

Ma vorresti ricevere tutta quella spazzatura se chiamassi TCP.ToString () su 100 pacchetti? Certo che no, sarebbe un sovraccarico di informazioni. La scelta facile e ovvia è anche la più sensata ...

Esponi ciò che le persone si aspettano di vedere:

  • Porta di origine
  • Porto di destinazione

Preferisco un output sensato che sia facile da analizzare per gli umani ma YMMV .

TCP:[destination:000, source:000]

Niente di complesso, l'output non è per le macchine da analizzare (cioè a meno che le persone non stiano abusando del tuo codice), lo scopo previsto è la leggibilità umana.

Ma per quanto riguarda il resto di quelle succose informazioni di cui ho parlato prima, non è utile anche questo? Ci arrivo, ma prima ...


ToString () uno dei metodi più preziosi e sottoutilizzati di tutti i tempi

Per due ragioni:

  1. Le persone non capiscono a cosa serve ToString ()
  2. Alla classe di base "Object" manca un altro metodo stringa altrettanto importante.

Motivo 1: non abusare dell'utilità di ToString ():

Molte persone usano ToString () per estrarre una semplice rappresentazione di stringa di un oggetto. Il manuale di C # afferma anche:

ToString è il principale metodo di formattazione in .NET Framework. Converte un oggetto nella sua rappresentazione di stringa in modo che sia adatto per la visualizzazione.

Schermo, non ulteriore elaborazione. Ciò non significa, prendi la mia bella rappresentazione di stringa del pacchetto TCP sopra e tira la porta sorgente usando una regex :: cringe ::.

Il diritto modo per fare le cose è chiamare ToString () direttamente sulla proprietà SourcePort (che BTW è un ushort quindi ToString () dovrebbe essere già disponibile).

Se hai bisogno di qualcosa di più robusto per impacchettare lo stato di un oggetto complesso per l'analisi della macchina, starai meglio usando una strategia di serializzazione strutturata.

Fortunatamente, tali strategie sono molto comuni:

  • ISerializable (C #)
  • Pickle (Python)
  • JSON (Javascript o qualsiasi linguaggio che lo implementa)
  • SAPONE
  • eccetera...

Nota: a meno che tu non stia utilizzando PHP perché, herp-derp, esiste una funzione per questo :: snicker ::

Motivo 2 - ToString () non è sufficiente:

Devo ancora vedere un linguaggio che lo implementa al centro, ma ho visto e utilizzato variazioni di questo approccio in natura.

Alcuni dei quali includono:

  • ToVerboseString ()
  • ToString (= verbose vero)

Fondamentalmente, quel disordine peloso dello stato di un pacchetto TCP dovrebbe essere descritto per la leggibilità umana. Per evitare di "battere un cavallo morto" parlando di TCP, "punterò il dito" sul caso n. 1 in cui penso che ToString () e ToVerboseString () siano sottoutilizzati ...

Caso d'uso - Array:

Se utilizzi principalmente una lingua, probabilmente ti trovi bene con l'approccio di quella lingua. Per le persone come me che saltano tra lingue diverse, il numero di approcci diversi può essere irritante.

Cioè, il numero di volte che questo mi ha irritato è maggiore della somma di tutte le dita di ogni dio indù messe insieme.

Ci sono diversi casi in cui le lingue di uso comune hack e un paio che ottiene è giusto . Alcuni richiedono la reinvenzione delle ruote, alcuni eseguono uno scarico superficiale, altri uno scarico profondo, nessuno di loro funziona come vorrei ...

Quello che chiedo è un approccio molto semplice:

print(array.ToString());

Uscite: "Array [x]" o "Array [x] [y]"

Dove x è il numero di elementi nella prima dimensione ey è il numero di elementi nella seconda dimensione o un valore che indica che la seconda dimensione è frastagliata (l'intervallo min / max forse?).

E:

print(array.ToVerboseString());

Produce l'intera botta in caratteri carini perché apprezzo le cose carine.

Spero che questo faccia luce su un argomento che mi ha infastidito per molto tempo. Per lo meno ho spruzzato un po 'di troll-bait per i PHP per downvote questa risposta.


Hai scritto: "Devo ancora vedere un linguaggio che lo implementa al centro". Mi sembra che Python si avvicini molto a questo; ad esempio, la stampa di un array fornisce tutti i suoi dati in modo conciso. Questa è una cosa che mi manca in C # / Java, anche se mi piace il loro rigore. E quando hai bisogno di andare un po 'oltre ToString (), sarebbe bello avere qualcosa come la sintassi di comprensione delle liste di Python; Immagino che string.Join () sia simile, sebbene meno flessibile.
Jon Coombs,

1
@JCoombs Non sono in disaccordo, le comprensioni sono fantastiche. Attraversare le strutture dati in Python tramite la comprensione rende la vita molto più semplice, ma questo approccio richiede comunque una conoscenza approfondita della struttura interna dell'oggetto. Qualcosa che non è sempre ovvio con le classi che sono state importate da una libreria esterna. È buona pratica per gli autori della libreria sovrascrivere ToString () e fornire un'utile rappresentazione leggibile dall'uomo, ma sarebbe anche utile avere un metodo di dump generale che restituisca la struttura dell'oggetto in un formato leggibile dall'uomo strutturato generale (ex JSON).
Evan Plaice

Ottimo punto. Quindi, invece di mostrare nient'altro che fondamentalmente un typeof, potrebbe auto-serializzarsi in qualcosa come JSON. (Finora, ho visto solo oggetti .NET serializzati in XML, ma sono nuovo in .NET) Ma allora il pericolo potrebbe essere la tentazione di trattare ToString () come leggibile dalla macchina? (Ad esempio, aspettati di poter deserializzarlo.)
Jon Coombs,

1
@JCoombs Sì, a livello funzionale JSON e XML hanno lo stesso scopo. Molte persone usano ToString come output leggibile dalla macchina; se ciò sia negativo o meno è discutibile. La mia più grande mania è, spesso, è un dolore produrre lo stato di un oggetto in un formato leggibile dall'uomo. L'implementazione di ToString () è spesso sottoutilizzata e leggere lo stato di un oggetto al di fuori degli elenchi di controllo del debugger è un problema. Le rappresentazioni serializzate sono buone come backup per la visualizzazione dell'intero stato di un oggetto, ma le migliori implementazioni di ToString sono l'opzione migliore.
Evan Plaice,

Se ToString()è pensato per il debug, perché è l'unico modo per estrarre l'intero testo da uno StringBuilder, una funzione importante?
Dan W

9

Si tratta di una buona pratica più di qualsiasi altra cosa, davvero.

ToString()viene utilizzato in molti luoghi per restituire una rappresentazione di stringa di un oggetto, generalmente per il consumo da parte di un essere umano. Spesso la stessa stringa può essere utilizzata per reidratare l'oggetto (pensa into DateTimeper esempio), ma non è sempre un dato (un albero per esempio, potrebbe avere un'utile rappresentazione di stringa che mostra semplicemente un Conteggio, ma chiaramente non puoi usare quello per ricostruirlo).

In particolare, il debugger lo utilizzerà per visualizzare la variabile nelle finestre di controllo, nelle finestre immediate, ecc., Quindi ToStringè effettivamente inestimabile per il debug.

In generale, inoltre, un tale tipo avrà spesso un membro esplicito che restituisce anche una stringa. Ad esempio, una coppia Lat / Long potrebbe avere ToDecimalDegreesche restituisce, "-10, 50"ad esempio, ma potrebbe anche avere ToDegreesMinutesSeconds, poiché questo è un altro formato per una coppia Lat / Long. Lo stesso tipo potrebbe quindi sovrascrivere ToStringuno di quelli per fornire un 'valore predefinito' per cose come il debug, o anche potenzialmente per cose come il rendering di pagine web (ad esempio, il @costrutto in Razor scrive il ToString()risultato di un'espressione non stringa nel flusso di output).


6

object.ToString()converte un oggetto nella sua rappresentazione di stringa. Se si desidera modificare ciò che viene restituito quando un utente chiama ToString()una classe che è stata creata, è necessario eseguire l'override ToString()di quella classe.


6

Anche se penso che le informazioni più utili siano già state fornite, aggiungerò i miei due centesimi:

  • ToString()è pensato per essere sovrascritto. La sua implementazione predefinita restituisce il nome del tipo che, sebbene possa essere utile a volte (in particolare quando si lavora con molti oggetti), non è sufficiente nella grande maggioranza delle volte.

  • Ricorda che, per scopi di debug, puoi fare affidamento su DebuggerDisplayAttribute. Puoi leggere di più al riguardo qui .

  • Di norma, sui POCO puoi sempre eseguire l'override ToString(). I POCO sono una rappresentazione strutturata dei dati, che di solito può diventare una stringa.

  • Progetta ToString per essere una rappresentazione testuale del tuo oggetto. Forse i suoi campi e dati principali, forse una descrizione di quanti articoli ci sono nella collezione, ecc.

  • Cerca sempre di adattare quella stringa in una singola riga e di avere solo le informazioni essenziali. Se hai una Personclasse con proprietà Nome, Indirizzo, Numero ecc., Restituisci solo i dati principali (Assegna un nome a un numero ID).

  • Fare attenzione a non sovrascrivere una buona implementazione di ToString(). Alcune classi di framework già implementano ToString(). Ignorare l'implementazione predefinita è una cosa negativa: le persone si aspettano un certo risultato ToString()e ne ottengono un altro.

Non aver paura di usare ToString(). L'unica cosa a cui fare attenzione è restituire informazioni sensibili. Oltre a questo, il rischio è minimo. Certo, come alcuni hanno sottolineato, altre classi useranno la tua ToString ogni volta che cercano informazioni. Ma diamine, quando restituire il nome del tipo sarà considerato meglio che ottenere alcune informazioni effettive?


5

Se non esegui l'override ToString, ottieni l'implementazione delle classi di base che, poiché Objectè solo il nome del tipo breve della classe.

Se vuoi qualche altra implementazione, più significativa o utile, ToStringsostituiscila.


Ciò può essere utile quando si utilizza un elenco del proprio tipo come origine dati per a ListBoxpoiché ToStringverrà visualizzato automaticamente.

Un'altra situtazione si verifica quando vuoi passare il tuo tipo a String.Formatcui invoca ToStringper ottenere una rappresentazione del tuo tipo.


4

Qualcosa che nessun altro ha ancora menzionato: ignorando ToString(), puoi anche considerare l'implementazione in IFormattablemodo da poter fare quanto segue:

 public override ToString() {
   return string.Format("{0,-20} {1, -20}", m_work, m_personal);
 }

 public ToString(string formatter) {
   string formattedEmail = this.ToString();
   switch (formatter.ToLower()) {
     case "w":
       formattedEmail = m_Work;
       break;
     case "p":
       formattedEmail = m_Personal;
       break;
     case "hw":
       formattedEmail = string.Format("mailto:{0}", m_Work);
       break;
   }
   return formattedEmail;
}

Che può essere utile.


Puoi fornire un esempio di una classe di framwork che fornisce quel metodo da sovrascrivere? L'unica cosa correlata di cui sono a conoscenza nel framework è l' IFormattibleinterfaccia.
tm1

@ tm1 Qualsiasi oggetto che eredita da System.Objectavrà un ToString()metodo sovrascrivibile , ma hai ragione sul fatto che il metodo del formattatore non dovrebbe essere overridee dovrebbe davvero fare riferimento IFormattibleall'interfaccia per una completa conformità.
Zhaph - Ben Duguid

Quasi - IFormattableprende un IFormatProviderparametro. Grazie per modificare il tuo post, però.
tm1

In effetti, ha due metodi, il valore che stavo esprimendo era in quello mostrato;)
Zhaph - Ben Duguid

3

Un vantaggio dell'override di ToString () è il supporto degli strumenti di Resharper: Alt + Ins -> "Formatting members" e scrive ToString () per te.


2

In alcuni casi rende più facile leggere i valori delle classi personalizzate nella finestra di controllo del debugger. Se so esattamente cosa voglio vedere nella finestra di controllo, quando sovrascrivo ToString con quelle informazioni, allora lo vedo.


1

Quando si definiscono le strutture (effettivamente le primitive dell'utente), trovo che sia una buona pratica avere metodi di corrispondenza ToStringe Parsee TryParse, in particolare per la serializzazione XML. In questo caso convertirai l'intero stato in una stringa, in modo che possa essere letto in seguito.

Le classi, tuttavia, sono strutture più composte che di solito saranno troppo complesse per l'uso ToString e Parse. I loro ToStringmetodi, invece di salvare l'intero stato, possono essere una semplice descrizione che ti aiuta a identificare il loro stato, come un identificatore univoco come un nome o un ID, o forse una quantità per un elenco.

Inoltre, come ha detto Robbie, l'override ToStringti consente di chiamare ToStringun riferimento semplice come il tipo object.


1

Puoi usarlo quando hai un oggetto con un significato non intuitivo di rappresentazione di stringa, come persona. Quindi, se hai bisogno, ad esempio, di stampare questa persona, puoi usare questo override per preparare il suo formato.


1

Il Object.ToStringmetodo deve essere utilizzato solo a scopo di debug. L'implementazione predefinita mostra il nome del tipo di oggetto che non è molto utile. Considerare di ignorare questo metodo per fornire informazioni migliori per la diagnostica e il debug. Tieni presente che le infrastrutture di registrazione spesso utilizzano anche il metodo ToString e quindi troverai questi frammenti di testo nei tuoi file di log.

Non restituire risorse di testo localizzate all'interno del Object.ToStringmetodo. Il motivo è che il metodo ToString dovrebbe sempre restituire qualcosa che lo sviluppatore può capire. Lo sviluppatore potrebbe non parlare tutte le lingue supportate dall'applicazione.

Implementa l' IFormattableinterfaccia quando desideri restituire un testo localizzato di facile utilizzo. Questa interfaccia definisce un sovraccarico ToString con i parametri formate formatProvider. Il formatProvider ti aiuta a formattare il testo in modo consapevole della cultura.

Vedi anche: Object.ToString e IFormattable


0

Più semplice dipende da come verrà utilizzata la tua proprietà. Se hai solo bisogno di formattare la stringa una volta, non ha molto senso sovrascriverla.

Tuttavia, sembra che tu stia sovrascrivendo il metodo ToString per non restituire i normali dati di stringa per la tua proprietà, ma per eseguire un modello di formattazione standard. Dato che stai usando string.format con padding.

Poiché hai detto che stai imparando, l'esercizio sembra colpire anche i principi fondamentali della programmazione orientata agli oggetti relativi all'incapsulamento e al riutilizzo del codice.

Il string.format che prende gli argomenti che hai impostato per il riempimento garantisce che la proprietà verrà formattata allo stesso modo ogni volta per qualsiasi codice che la chiama. Inoltre, andando avanti devi solo cambiarlo in un posto invece di molti.

Ottima domanda e anche alcune ottime risposte!


0

Trovo utile sovrascrivere il metodo ToString sulle classi di entità in quanto aiuta a identificare rapidamente i problemi nei test, specialmente quando un'asserzione fallisce, la console di test richiamerà il metodo ToString sull'oggetto.

Ma in accordo con quanto detto prima si tratta di fornire una rappresentazione leggibile dall'uomo dell'oggetto in questione.


0

Sono soddisfatto delle linee guida del framework a cui si fa riferimento in altre risposte. Tuttavia, vorrei sottolineare la visualizzazione e gli scopi di debug.

Fai attenzione a come usi il ToStringtuo codice. Il codice non dovrebbe fare affidamento sulla rappresentazione di stringa di un oggetto. Se lo fa, dovresti assolutamente fornire il rispettivoParse metodi.

Poiché ToStringpuò essere utilizzato ovunque, può essere un punto dolente per la manutenibilità se si desidera modificare la rappresentazione di stringa di un oggetto in un momento successivo. Non puoi semplicemente esaminare la gerarchia delle chiamate in questo caso per studiare se un codice si interromperà.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.