Domanda

Ho letto tutte le domande relative a questo argomento e forniscono tutte le ragioni per cui un costruttore predefinito su struct non è disponibile in C #, ma non ho ancora trovato nessuno che suggerisca una linea d'azione generale di fronte questa situazione.

La soluzione ovvia è semplicemente convertire class in IsValid e gestirne le conseguenze.

Esistono altre opzioni per mantenerlo come internal?

Mi sono imbattuto in questa situazione con uno dei nostri oggetti API di commercio interno. Il designer lo ha convertito da <=> a <=> e ora il costruttore predefinito (che prima era privato) lascia l'oggetto in uno stato non valido.

Ho pensato che se vogliamo mantenere l'oggetto come <=>, dovrebbe essere introdotto un meccanismo per verificare la validità dello stato (qualcosa come una proprietà <=>). Ho incontrato molta resistenza e una spiegazione di & Quot; chiunque usi l'API non dovrebbe usare il costruttore predefinito, & Quot; un commento che certamente ha sollevato le mie sopracciglia. (Nota: l'oggetto in questione è costruito & Quot; correttamente & Quot; tramite metodi statici di fabbrica e tutti gli altri costruttori sono <=>.)

Tutti stanno semplicemente convertendo le loro <=> s in <=> es in questa situazione senza pensarci due volte?

Modifica: vorrei vedere alcuni suggerimenti su come mantenere questo tipo di oggetto come <=> - l'oggetto in questione sopra è molto più adatto come <=> che come <=>.

È stato utile?

Soluzione

Per un struct, si progetta il tipo in modo che l'istanza costruita predefinita (campi tutti zero) sia uno stato valido. Non [ non ] utilizzare arbitrariamente class invece di <=> senza una buona ragione: non c'è niente di sbagliato nell'usare un tipo di riferimento immutabile.

I miei suggerimenti:

  • Assicurati che il motivo dell'uso di <=> sia valido (un profiler [reale] ha rivelato significativi problemi di prestazioni derivanti dalla forte allocazione di un oggetto molto leggero).
  • Progetta il tipo in modo che l'istanza costruita predefinita sia valida.
  • Se il design del tipo è dettato da vincoli di interoperabilità nativi / COM, avvolgere la funzionalità e non esporre <=> all'esterno del wrapper (tipo annidato privato). In questo modo è possibile documentare e verificare facilmente l'uso corretto dei requisiti di tipo vincolato.

Altri suggerimenti

La ragione di ciò è che una struttura (un'istanza di System.ValueType) è trattata appositamente dal CLR: è inizializzata con tutti i campi pari a 0 (o predefiniti). Non è nemmeno necessario crearne uno, basta dichiararlo. Ecco perché sono richiesti i costruttori predefiniti.

Puoi aggirare il problema in due modi:

  1. Crea una proprietà come IsValid per indicare se è una struttura valida, come indichi e
  2. in .Net 2.0 considera l'utilizzo di Nullable < T > per consentire una struttura non inizializzata (null).

Cambiare la struttura in una classe può avere alcune conseguenze molto sottili (in termini di utilizzo della memoria e identità dell'oggetto che emergono di più in un ambiente multithread) e NullReferenceExceptions non così sottile ma difficile da debug per oggetti non inizializzati.

/ p>

Il motivo per cui non è possibile definire un costruttore predefinito è illustrato dalla seguente espressione:

new MyStruct[1000];

Hai 3 opzioni qui

  1. chiamando il costruttore predefinito 1000 volte o
  2. creazione di dati corrotti (si noti che una struttura può contenere riferimenti; se non si inizializza o si cancella il riferimento, è possibile accedere potenzialmente alla memoria arbitraria) oppure
  3. cancella la memoria allocata con zero (a livello di byte).

.NET fa lo stesso sia per le strutture che per le classi: i campi e gli elementi dell'array sono oscurati con zero. Ciò comporta anche un comportamento più coerente tra strutture e classi e nessun codice non sicuro. Inoltre, consente al framework .NET di non specializzare qualcosa come new byte[1000].

E questo è il costruttore predefinito per le strutture .NET richiede e si prende cura di se stesso: azzera tutti i byte.

Ora, per gestirlo, hai un paio di opzioni:

  • Aggiungi una proprietà Am-I-Initialized alla struttura (come HasValue su Nullable).
  • Consenti alla struttura azzerata di essere un valore valido (come 0 è un valore valido per un decimale).
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top