.net in - Perché C#non supporta il ritorno dei riferimenti?




parameters string (5)

Ho letto che .NET supporta il ritorno dei riferimenti, ma C # non lo fa. C'è una ragione speciale? Perché non posso fare qualcosa come:

static ref int Max(ref int x, ref int y) 
{ 
  if (x > y) 
    return ref x; 
  else 
    return ref y; 
} 

Answers

Questa domanda è stata oggetto del mio blog il 23 giugno 2011 . Grazie per la bella domanda!

Il team C # sta considerando questo per C # 7. Vedere https://github.com/dotnet/roslyn/issues/5233 per i dettagli.

AGGIORNAMENTO: la funzione è arrivata in C # 7!

Hai ragione; .NET supporta metodi che restituiscono riferimenti gestiti a variabili. .NET supporta anche variabili locali che contengono riferimenti gestiti ad altre variabili. (Si noti tuttavia che .NET non supporta campi o matrici che contengono riferimenti gestiti ad altre variabili, poiché ciò complica eccessivamente la storia della raccolta dati obsoleti. Anche i tipi di "riferimento gestito alle variabili" non sono convertibili in oggetto e pertanto non possono essere utilizzati come digitare argomenti per tipi o metodi generici.)

Il commentatore "RPM1984" per qualche ragione ha chiesto una citazione per questo fatto. RPM1984 Vi incoraggio a leggere la specifica CLI Partition I Section 8.2.1.1, "Puntatori gestiti e tipi correlati" per informazioni su questa funzionalità di .NET.

È completamente possibile creare una versione di C # che supporti entrambe queste funzionalità. Potresti quindi fare cose del genere

static ref int Max(ref int x, ref int y) 
{ 
  if (x > y) 
    return ref x; 
  else 
    return ref y; 
} 

e poi chiamalo con

int a = 123;
int b = 456; 
ref int c = ref Max(ref a, ref b); 
c += 100;
Console.WriteLine(b); // 556!

So empiricamente che è possibile creare una versione di C # che supporti queste funzionalità perché l'ho fatto . I programmatori avanzati, in particolare le persone che eseguono il porting di codice C ++ non gestito, spesso ci chiedono più capacità in C ++ di fare cose con riferimenti senza dover uscire dal grande martello di usare effettivamente puntatori e bloccare la memoria dappertutto. Utilizzando i riferimenti gestiti si ottengono questi benefici senza pagare il costo di rovinare le prestazioni della raccolta dei dati inutili.

Abbiamo preso in considerazione questa funzione e ne abbiamo implementata abbastanza da mostrarla agli altri team interni per ottenere il loro feedback. Tuttavia, in questo momento sulla base delle nostre ricerche , riteniamo che la funzione non abbia un ricorso sufficientemente ampio o casi di utilizzo convincenti per trasformarlo in una vera e propria funzione linguistica supportata . Abbiamo altre priorità più alte e una quantità limitata di tempo e sforzi disponibili, quindi non faremo questa funzione in tempi brevi.

Inoltre, l'esecuzione corretta richiederebbe alcune modifiche al CLR. In questo momento il CLR considera i metodi di restituzione come legali ma non verificabili perché non abbiamo un rilevatore che rilevi questa situazione:

ref int M1(ref int x)
{
    return ref x;
}

ref int M2()
{
    int y = 123;
    return ref M1(ref y); // Trouble!
}

int M3()
{
    ref int z = ref M2();
    return z;
}

M3 restituisce il contenuto della variabile locale di M2, ma la durata di tale variabile è terminata! È possibile scrivere un rivelatore che determina l'uso di ref-return che chiaramente non violano la sicurezza dello stack. Quello che faremmo è scrivere un tale rilevatore, e se il rivelatore non fosse in grado di dimostrare la sicurezza dello stack, allora non permetteremmo l'uso dei ref-ref in quella parte del programma. Non è un'enorme quantità di lavoro di sviluppo fare così, ma è molto oneroso per i team di test assicurarsi che abbiamo davvero tutti i casi. È solo un'altra cosa che aumenta il costo della funzionalità al punto in cui in questo momento i benefici non superano i costi.

Se riesci a descrivermi perché desideri questa funzione, lo apprezzerei davvero . Più informazioni abbiamo dai clienti reali sul motivo per cui lo vogliono, più è probabile che un giorno entrerà nel prodotto. È una caratteristica carina e mi piacerebbe poterla avere in qualche modo con i clienti se c'è un interesse sufficiente.

(Vedi anche domande correlate È possibile restituire un riferimento ad una variabile in C #? E Posso usare un riferimento all'interno di una funzione C # come C ++? )


Stai parlando di metodi che restituiscono un riferimento a un tipo di valore. L'unico esempio incorporato in C # che io conosca è l'accessorio di array di un tipo di valore:

public struct Point
{
    public int X { get; set; }
    public int Y { get; set; }
}

e ora crea una matrice di quella struttura:

var points = new Point[10];
points[0].X = 1;
points[0].Y = 2;

In questo caso i points[0] , l' indicizzatore di array, restituisce un riferimento a struct. È impossibile scrivere il proprio indicizzatore (ad esempio per una raccolta personalizzata), che ha lo stesso comportamento "restituisce un riferimento".

Non ho progettato il linguaggio C # quindi non conosco tutti i ragionamenti alla base del non supportarlo, ma penso che la risposta breve potrebbe essere: possiamo andare d'accordo senza.


C # 7.0 ha il supporto per la restituzione dei riferimenti. Vedi la mia risposta here .


Puoi sempre fare qualcosa del tipo:

public delegate void MyByRefConsumer<T>(ref T val);

public void DoSomethingWithValueType(MyByRefConsumer<int> c)
{
        int x = 2;
        c(ref x);
        //Handle potentially changed x...
}

La prima parte della tua domanda (come ottenere i byte) ha già ricevuto risposta da altri: guarda nello spazio dei nomi System.Text.Encoding .

Tratterò la tua domanda di follow-up: perché hai bisogno di scegliere una codifica? Perché non puoi ottenerlo dalla stessa classe di stringhe?

La risposta è in due parti.

Prima di tutto, i byte usati internamente dalla classe string non hanno importanza , e ogni volta che si presume lo facciano probabilmente introducendo un bug.

Se il tuo programma è interamente all'interno del mondo .Net, allora non devi preoccuparti di ottenere array di byte per le stringhe, anche se stai inviando dati attraverso una rete. Invece, utilizzare la serializzazione .Net per preoccuparsi della trasmissione dei dati. Non ti preoccupare più dei byte effettivi: il formattatore di serializzazione lo fa per te.

D'altra parte, cosa succede se si inviano questi byte da qualche parte che non si può garantire l'estrazione dei dati da un flusso serializzato .Net? In questo caso hai sicuramente bisogno di preoccuparti della codifica, perché ovviamente questo sistema esterno si preoccupa. Quindi, di nuovo, i byte interni utilizzati dalla stringa non contano: è necessario scegliere una codifica in modo da poter essere espliciti su questa codifica sul lato ricevente, anche se è la stessa codifica utilizzata internamente da .Net.

Capisco che in questo caso potresti preferire utilizzare i byte effettivi memorizzati dalla variabile stringa nella memoria, ove possibile, con l'idea che potrebbe salvare del lavoro creando il flusso di byte. Tuttavia, l'ho messo per te non è importante rispetto al fare in modo che il tuo output sia compreso dall'altra parte, e per garantire che tu debba essere esplicito con la tua codifica. Inoltre, se vuoi davvero abbinare i tuoi byte interni, puoi già scegliere la codifica Unicode e ottenere così un risparmio di prestazioni.

Il che mi porta alla seconda parte ... la scelta della codifica Unicode sta dicendo a .Net di usare i byte sottostanti. È necessario scegliere questa codifica, perché quando esce Unicode-Plus un po 'nuovo, il runtime .Net deve essere libero di utilizzare questo modello di codifica più recente e migliore senza interrompere il programma. Ma, per il momento (e il futuro prevedibile), scegliere la codifica Unicode ti dà quello che vuoi.

È anche importante capire che la stringa deve essere riscritta sul filo, e ciò implica almeno una certa traduzione del pattern di bit anche quando si utilizza una codifica corrispondente . Il computer deve tenere conto di cose come Big vs Little Endian, ordine dei byte di rete, pacchetti, informazioni sulla sessione, ecc.





c# .net reference return-type