Categories
Uncategorized

Benvenuto C # 9.012/06/2020

TheMummichogblog è un partecipante al Amazon Services LLC Associates programma, un programma di affiliazione pubblicitario progettato per fornire un mezzo per siti per guadagnare tariffe pubblicitarie con la pubblicità e il link al amazon.com. Amazon, il logo di Amazon, AmazonSupply, e il logo AmazonSupply sono marchi di Amazon.com, Inc. o delle sue affiliate.

--------------------------------------------------------------------------------------------------
Booking.com
La fede รจ fondamento delle cose che si sperano e prova di quelle che non si vedono.
----------------------------------------------------------------------------------------------

Benvenuto C # 9.0
Mads Torgersen
Mads

20 maggio 2020

C # 9.0 sta prendendo forma, e mi piacerebbe condividere il nostro pensiero su alcune delle caratteristiche principali che stiamo aggiungendo a questo la prossima versione del linguaggio.

Con ogni nuova versione di C # ci sforziamo per una maggiore chiarezza e semplicità in scenari di codifica comuni, e C # 9.0 non fa eccezione. Un obiettivo particolare questa volta sostiene terso e rappresentazione immutabile di forme di dati.

tuffo di entrare!

Init proprietà di sola
inizializzatori di oggetti sono abbastanza impressionante. Essi danno il cliente di un tipo un formato molto flessibile e leggibile per la creazione di un oggetto, e sono particolarmente grande per la creazione di oggetti nidificato in cui viene creato un intero albero di oggetti in una volta sola. Ecco un semplice:

nuova persona
{
FirstName = “Scott”,
Cognome = “Hunter”
}
inizializzatori oggetto anche liberare il tipo di autore dalla scrittura un sacco di testo standard di costruzione – tutto quello che devono fare è scrivere alcune proprietà!

Person public class
{
public string FirstName {get; impostato; }
public string Cognome {get; impostato; }
}
L’unico grande limite oggi è che le proprietà devono essere mutabile per inizializzatori oggetto al lavoro: Essi funzionano in primo luogo denominando costruttore dell’oggetto (l’impostazione predefinita, senza parametri uno in questo caso) e poi assegnare ai setter di proprietà.

proprietà init-unica correzione che! Essi presentano una funzione di accesso init che è una variante di accesso set che può essere chiamato solo durante l’inizializzazione oggetto:

Person public class
{
public string FirstName {get; dentro; }
public string Cognome {get; dentro; }
}
Con questa dichiarazione, il codice del client di cui sopra è ancora legale, ma qualsiasi successiva assegnazione alle proprietà FirstName e LastName è un errore.

di accesso init e campi di sola lettura
A causa di accesso init possono essere chiamati solo durante l’inizializzazione, essi sono autorizzati a mutare i campi di sola lettura della classe contenitrice, proprio come si può in un costruttore.

Person public class
{
privato stringa di sola lettura firstName;
stringa di sola lettura privata cognome;

Public string FirstName
{
get => firstName;
init => firstName = (valore ?? gettare nuova ArgumentNullException (nameof (FirstName)));
}
Cognome public string
{
get => lastName;
init => lastName = (valore ?? gettare nuova ArgumentNullException (nameof (Cognome)));
}
}
Records
proprietà init-solo sono grandi se si vuole fare singole proprietà immutabile. Se si desidera che l’intero oggetto sia immutabile e si comportano come un valore, allora si dovrebbe considerare dichiarandolo come un record:

Persona di classe di dati pubblici
{
public string FirstName {get; dentro; }
public string Cognome {get; dentro; }
}
I dati sulle parole chiave sui marchi di dichiarazione di classe come un record. Questo impregna con diversi valore-come ulteriore comportamenti, che ci scavare nel seguito. In generale, i record sono fatti per essere visti più come “valori” – di dati! – e meno come oggetti. Essi non sono destinati ad avere lo stato Encapsulated mutevole. Invece rappresentate cambiare nel tempo con la creazione di nuovi record che rappresentano il nuovo stato. Essi sono definiti non dalla loro identità, ma per il loro contenuto.

Con-espressioni
Quando si lavora con dati immutabili, un modello comune è quello di creare nuovi valori da quelli esistenti per rappresentare un nuovo stato. Per esempio, se la nostra persona dovesse cambiare il proprio cognome avremmo rappresentiamo come un nuovo oggetto che è una copia di quello vecchio, se non con un diverso cognome. Questa tecnica viene spesso definita come la mutazione non distruttivo. Invece di rappresentare la persona nel corso del tempo, il record rappresenta lo stato della persona in un dato momento.

Per contribuire a questo stile di programmazione, record consentono per un nuovo tipo di espressione; la con-espressione:

var = otherPerson persona con {Cognome = “Hanselman”};
Con-espressioni utilizzano inizializzazione degli oggetti sintassi per lo stato cosa c’è di diverso nel nuovo oggetto dal vecchio oggetto. È possibile specificare più proprietà.

Un record definisce implicitamente un protetto “costruttore di copia” – un costruttore che prende un oggetto record esistente e lo copia campo per campo a quello nuovo:

protetta soggetto (persona originale) {/ * copiare tutti i campi * /} // generato
Il con l’espressione provoca il costruttore di copia per ottenere chiamato, e poi applica l’inizializzatore di oggetto sulla parte superiore per modificare le proprietà di conseguenza.

Se non ti piace il comportamento predefinito del costruttore di copia generato è possibile definire il proprio posto, e che saranno prelevati dal con l’espressione.

uguaglianza basata sul valore
Tutti gli oggetti ereditano un metodo virtuale Equals (Object) dalla classe oggetto. Questo viene utilizzato come base per le Object.Equals (oggetto, oggetto) metodo statico quando entrambi i parametri sono non nulli.

Le strutture ignorare questo per avere “l’uguaglianza basato sul valore”, confrontando ogni campo della struct chiamando Equals su di loro in modo ricorsivo. Records fanno lo stesso.

Ciò significa che, in conformità con il loro “valore-ness” due oggetti di registrazione possono essere uguali l’uno all’altro senza essere lo stesso oggetto. Per esempio, se modifichiamo il cognome della persona modificato di nuovo:

var = originalPerson otherPerson con {Cognome = “Hunter”};
Vorremmo ora hanno ReferenceEquals (persona, originalPerson) = false (non sono lo stesso oggetto), ma Equals (persona, originalPerson) = TRUE (hanno lo stesso valore).

Se non ti piace il comportamento predefinito di campo per campo comparazione del Eguali di override generato, è possibile scrivere il proprio posto. Hai solo bisogno di stare attenti che si capisce come valore a base di opere di uguaglianza nei record, soprattutto quando l’ereditarietà è coinvolto, che torneremo al di sotto.

Insieme con Eguali basate sul valore c’è anche un GetHashCode () Azionamento basato sul valore di andare con esso.

membri di dati
I record sono prevalentemente destinati ad essere immutabile, con init di sola proprietà pubbliche che possono essere non distruttiva modificato attraverso con-espressioni. Al fine di ottimizzare per quel caso comune, record cambiano le impostazioni predefinite di ciò che una semplice dichiarazione membro dei mezzi FirstName stringa modulo. Invece di un campo implicitamente privata, come in altre dichiarazioni di classe e struct, nei record questo è considerato una scorciatoia per un pubblico, init-solo auto-proprietà! Così, la dichiarazione:

classe di dati pubblici Person {string FirstName; stringa Cognome; }
Significa esattamente la stessa di quella che avevamo prima:

Persona di classe di dati pubblici
{
public string FirstName {get; dentro; }
public string Cognome {get; dentro; }
}
Pensiamo che questo rende per le dichiarazioni di registrazione belle e chiare. Se si vuole veramente un campo privato, si può semplicemente aggiungere il modificatore privato esplicitamente:

stringa firstName privato;
record posizionali
A volte è utile avere un approccio più posizionale a un record, in cui il suo contenuto viene fornito mediante argomenti del costruttore, e può essere estratto con decostruzione posizionale.

E ‘perfettamente possibile specificare il proprio costruttore e decostruttore in un record:

Persona di classe di dati pubblici
{
stringa FirstName;
stringa Cognome;
pubblico Persona (stringa firstName, lastName stringa)
=> (Nome, Cognome) = (Nome, Cognome);
public void Deconstruct (fuori firstName stringa, la stringa di lastName)
=> (Nome, cognome) = (Nome, Cognome);
}
Ma c’è una sintassi molto più breve per esprimere esattamente la stessa cosa (modulo involucro di nomi dei parametri):

classe di dati pubblici Person (stringa Nome, Cognome stringa);
Questo dichiara le proprietà auto-init-only pubblici e il costruttore e il decostruttore, in modo che si può scrivere:

var persona = new Person ( “Scott”, “Hunter”); // costruzione posizionale
var (f, l) = persona; // decostruzione posizionale
Se non ti piace l’auto-immobile generato è possibile definire la vostra proprietà con lo stesso nome, invece, e il costruttore generato e decostruttore sarà solo utilizzare quello.

Records e la mutazione
La semantica basate sul valore di un record non gel bene con stato mutevole. Immaginate di mettere un oggetto record in un dizionario. Trovando di nuovo dipende da Equals e (a volte) GetHashCode. Ma se il record cambia il suo stato, sarà anche cambiare ciò che è uguale a! Potremmo non essere in grado di trovare di nuovo! In un’implementazione tabella hash potrebbe anche corrompere la struttura dei dati, dal momento che il posizionamento è basato sul codice hash che ha “in arrivo”!

Probabilmente ci sono alcuni usi avanzati validi di mutevole all’interno dello stato di record, in particolare per il caching. Ma il lavoro manuale coinvolti nella ignorando i comportamenti predefiniti di ignorare tale stato è probabile che sia considerevole.

Con espressioni e l’eredità
uguaglianza basata sul valore e la mutazione non distruttive sono notoriamente difficili quando combinato con l’ereditarietà. Aggiungiamo una classe derivata Student registrazione al nostro esempio in esecuzione:

classe di dati pubblici Person {string FirstName; stringa Cognome; }
dati pubblici classe Student: Person {int ID; }
E cominciamo il nostro esempio con espressione da realtà la creazione di uno Studente, ma la memorizzazione in una variabile Persona:

persona Person = new Student {FirstName = “Scott”, Cognome = “Hunter”, ID = GetNewId ()};
otherPerson = persona con {Cognome = “Hanselman”};
Al punto di che, con espressione nell’ultima riga il compilatore non ha idea che la persona in realtà contiene uno Studente. Eppure, la nuova persona non sarebbe una copia corretta se non fosse in realtà un oggetto Student, con lo stesso ID come il primo copiato.

C # fa questo lavoro. Records hanno un metodo virtuale nascosto che è affidato “clonazione” l’intero oggetto. Ogni tipo di record derivato sovrascrive questo metodo per chiamare il costruttore di copia di quel tipo, e il costruttore di copia di un record di catene derivati ​​al costruttore di copia del record di base. A con espressione chiama semplicemente il metodo “clone” nascosti e si applica l’inizializzazione degli oggetti al risultato.

uguaglianza basata sul valore e l’ereditarietà
Analogamente al supporto con espressione, eguaglianza basata sui valori deve essere anche “virtuale”, nel senso che gli studenti hanno bisogno di confrontare tutti i campi degli studenti, anche se il tipo noto staticamente al punto di confronto è un tipo di base come persona . Ciò è facilmente ottenibile eseguendo l’override del metodo Equals già virtuale.

Tuttavia, v’è un’ulteriore sfida con uguaglianza: Che cosa succede se si confrontano due diversi tipi di persona? Non possiamo lasciare che uno di loro decidono che l’uguaglianza da applicare: la parità dovrebbe essere simmetrica, in modo che il risultato dovrebbe essere lo stesso indipendentemente da quale dei due oggetti venire prima. In altre parole, devono concordare l’uguaglianza viene applicato!

Un esempio per illustrare il problema:

person1 Person = new Person {FirstName = “Scott”, Cognome = “Hunter”};
Persona persona2 = new Student {FirstName = “Scott”, Cognome = “Hunter”, ID = GetNewId ()};
Sono i due oggetti uguali tra loro? person1 potrebbe pensare così, dal momento che Person2 ha tutte le cose persona giusta, ma Person2 permetto di dissentire! Dobbiamo fare in modo che entrambi concordano sul fatto che essi sono oggetti diversi.

Ancora una volta, C # si prende cura di questo per voi automaticamente. Il modo in cui è fatto è che i documenti hanno una proprietà virtuale protetta denominata EqualityContract. Ogni override registrare derivati ​​IT, e al fine di confrontare uguali, i due oggetti hanno la stessa mosti EqualityContract.

programmi di alto livello
Scrivere un semplice programma in C # richiede una notevole quantità di codice boilerplate:

using System;
Programma di classe
{
static void Main ()
{
Console.WriteLine ( “Ciao Mondo!”);
}
}
Questo non è solo schiacciante per i principianti della lingua, ma ingombra il codice e aggiunge livelli di rientro.

In C # 9.0 si può solo scegliere di scrivere il programma principale al livello più alto, invece:

using System;

Console.WriteLine ( “Ciao Mondo!”);
Ogni dichiarazione è permesso. Il programma deve essere successiva alla usings e prima di qualsiasi dichiarazione di tipo o spazio nel file, e si può fare solo in un unico file, proprio come si può avere solo un metodo principale di oggi.

Se si desidera restituire un codice di stato si può fare. Se si vuole le cose attendono si può fare. E se si vuole argomenti della riga di comando di accesso, args è disponibile come parametro di “magia”.

funzioni locali sono una forma di dichiarazione e sono anche permesso al programma di livello superiore. Si tratta di un errore di chiamarli da qualsiasi luogo al di fuori della sezione dichiarazione livello superiore.

pattern matching migliorato
Diversi nuovi tipi di modelli sono stati aggiunti in C # 9.0. Diamo un’occhiata a loro nel contesto di questo frammento di codice dal tutorial pattern matching:

public static decimale CalculateToll (veicolo oggetto) =>
interruttore veicolo
{

DeliveryTruck t quando t.GrossWeightClass> 5000 => 10.00m + 5,00 m,
DeliveryTruck t quando t.GrossWeightClass 10.00m – 2.00m,
DeliveryTruck _ => 10.00m,

_ => Throw new ArgumentException ( “Non è un noto tipo di veicolo”, nameof (veicolo))
};
modelli di tipo semplice
Attualmente, un modello di tipo ha bisogno di dichiarare un identificatore quando il tipo di partite – anche se questo identificatore è uno scarto _, come in DeliveryTruck _ sopra. Ma ora si può solo scrivere il tipo:

DeliveryTruck => 10.00m,
modelli relazionali
C # 9.0 introduce modelli corrispondenti agli operatori relazionali

DeliveryTruck t quando l’interruttore t.GrossWeightClass
{
> 5000 => 10.00m + 5,00 m,
10.00m – 2.00m,
_ => 10.00m,
},
Qui> 5000 e

schemi logici
Infine è possibile combinare i modelli con gli operatori logici AND, OR e non, precisato come le parole per evitare confusione con gli operatori utilizzati nelle espressioni. Ad esempio, i casi dell’interruttore nidificata sopra potrebbero essere messe in ordine ascendente in questo modo:

DeliveryTruck t quando l’interruttore t.GrossWeightClass
{
10.00m – 2.00m,
> = 3000 e 10.00m,
> 5000 => 10.00m + 5,00 m,
},
Il caso mezzo ci usa e per combinare due schemi relazionali e formano un modello che rappresenta un intervallo.

Un utilizzo comune della non modello sarà applicandolo alla costante modello nullo, come in non nullo. Per esempio siamo in grado di dividere la gestione dei casi sconosciuti a seconda che essi sono nulli:

non nullo => throw new ArgumentException ($ “Non è un noto tipo di veicolo: {} veicolo”, nameof (veicolo)),
null => throw new ArgumentNullException (nameof (veicolo))
Inoltre non sta per essere conveniente se-condizioni contenente Is-espressioni in cui, invece di ingombranti doppie parentesi:

if (! (e è Cliente)) {…}
Si può solo dire che

se (e non è cliente) {…}
Migliorata tipizzazione bersaglio
“Tipizzazione Target” è un termine che usiamo per quando un’espressione prende il tipo dal contesto in cui è in uso. Per esempio nullo e le espressioni lambda sono sempre bersaglio digitato.

In C # 9.0 alcune espressioni che non erano in precedenza bersaglio digitati diventano in grado di essere guidati dal loro contesto.

Target-typed nuove espressioni
nuove espressioni in C # hanno sempre richiesto un tipo da specificare (tranne che per le espressioni di matrice implicitamente tipizzate). Ora si può tralasciare il tipo se c’è un tipo chiaro che le espressioni viene assegnato a.

Punto p = new (3, 5);
Obiettivo digitato ?? e ?:
A volte condizionale ?? e:? le espressioni non hanno un tipo condiviso evidente tra i rami. Tali casi non riescono oggi, ma C # 9.0 permetterà loro se c’è un tipo di destinazione che entrambi i rami convertire in:

Persona persona = studente ?? cliente; // tipo di base condivisa
int? risultato = b? 0: nullo; // tipo valore nullable
ritorna covarianti
A volte è utile per esprimere che un metodo di sostituzione in una classe derivata ha un tipo di ritorno più specifico rispetto alla dichiarazione nel tipo di base. C # 9.0 consente che:

Animal classe astratta
{
public abstract alimentari GetFood ();

}
Classe di Tiger: Animal
{
public override Carne GetFood () => …;
}
E altro ancora…
Il posto migliore per controllare il set completo di caratteristiche imminenti per C # 9.0 e seguire il loro completamento è lo stato caratteristica del linguaggio sul repo Roslyn (C # / VB Compiler) GitHub.

Felice Hacking!

Mads Torgersen
Mads Torgersen
C # Lead Designer, .NET squadra

Welcome to C# 9.0

Amazon e il logo di Amazon sono marchi di Amazon.com, Inc., o delle sue affiliate.