2010-12-27 10 views
29

Posso restituire un riferimento ad un valore doppio ad esempio?È possibile restituire un riferimento a una variabile in C#?

Questo è quello che voglio fare:

ref double GetElement() 
{ 
    ...... 
    // Calculate x,y,z 
    return ref doubleArray[x,y,z]; 
} 

Per usarlo come questo

void func() 
{ 
    GetElement()=5.0; 
} 

E 'come tornare un doppio puntatore in C++ ... So che il mio modo di ha scritto che è sbagliato .. ma c'è un modo corretto per farlo?

+0

vuoi assegnare l'elemento alla matrice o ottenere il suo valore? Vuoi una funzione che legge qualcosa o scrive qualcosa? – Axarydax

+0

Voglio assegnare un valore nella funzione chiamante .. – Betamoo

+0

Non solo non puoi fare questo, si sta cercando di restituire un riferimento a un'istanza di un tipo di valore. Non so nemmeno cosa significherebbe. –

risposta

6

Valore i tipi in C# vengono sempre passati per valore. Gli oggetti hanno sempre il loro riferimento passato per valore. Questo cambia nel codice "non sicuro" come sottolinea Axarydax.

Il modo più semplice e sicuro per evitare questo vincolo è assicurarsi che il doppio sia collegato a un oggetto in qualche modo.

public class MyObjectWithADouble { 
    public double Element {get; set;} // property is optional, but preferred. 
} 

... 
var obj = new MyObjectWithADouble(); 
obj.Element = 5.0 

Voglio anche sottolineare che sono un po 'confusi su come si prevede l'assegnazione di un doppio a una matrice tridimensionale. Potresti voler chiarire che cosa stai andando.

Penso di capire un po 'meglio a cosa stai andando ora. Si desidera restituire la posizione del valore in un determinato array e quindi essere in grado di modificare il valore in quella posizione. Questo schema rompe alcuni dei paradigmi previsti di C#, quindi suggerirei di prendere in considerazione altri modi per ottenere ciò che stai cercando. Ma se fa veramente senso per farlo, mi piacerebbe fare qualcosa di più simile a questo:

public class 3dArrayLocation {public int X; public int Y; public int Z;} 

... 

public 3dArrayLocation GetElementLocation(...) 
{ 
    // calculate x, y, and z 
    return new 3dArrayLocation {X = x, Y = y, Z = z} 
} 

... 

var location = GetElementLocation(...); 
doubleArray[location.X, location.Y, location.Z] = 5.0; 
+0

Non preoccuparti, l'array non è di 3 dimensioni ma 8 dimensioni ... Alcuni sistemi di apprendimento automatico con Q-Learning hanno bisogno di questo :) – Betamoo

+1

@Betamoo: suona come tutti i tipi di divertimento. Vedi la mia modifica. – StriplingWarrior

8

No, questo non è possibile in C#. Puoi solo passare i parametri per riferimento.

Tuttavia, si potrebbe ottenere lo stesso risultato con una proprietà:

double Element 
{ 
    get { return doubleArray[x,y,z]; } 
    set { doubleArray[x,y,z] = value; } 
} 

void func() 
{ 
    Element = 5.0; 
} 
6

È potrebbe farlo in unsafe code e hanno un metodo che restituisce un puntatore a doppio:

unsafe double* GetElementP(){ 
... 
} 
+0

Anche se questo è possibile, non voglio raccomandare esso ...ci sono probabilmente modi migliori per risolvere il problema, ma l'OP deve fornire maggiori dettagli su ciò che vuole fare –

+0

Dovresti sistemare la matrice in modo che il garbage collector non la sposti. –

+1

@Eric: So che questo potrebbe essere un po 'off-topic per voi, ma sarebbe terribilmente bello se qualcuno bloggato su come C++/CLI del 'interior_ptr' e' mappa pin_ptr' nel sistema tipo CLR, come le variabili C# s' puntatore confrontano, e se c'è qualche equivalente in C# per i puntatori C++/CLI. –

1

Dopo qualche pensiero, perché non inviare il valore da impostare con la funzione in questo modo:

void SetElement(double value) 
{ 
    ...... 
    // Calculate x,y,z 
    doubleArray[x,y,z]=value; 
} 

e usarlo:

void func() 
{ 
    SetElement(5.0); 
} 

Tuttavia, devo ancora scegliere una delle tue risposte utile ...

40

UPDAT E: La caratteristica desiderata è ora supportato in C# 7.


Il sistema di tipo CLR supporta metodi di Ref-ritorno, e ho scritto un prototipo sperimentale del compilatore C# che supporta la funzione che si desidera. (Il prototipo implementa anche variabili locali ref-typed, ma i campi ref-typed sono illegali nel sistema di tipo CLR.)

Hai raggiunto esattamente la sintassi che ho scelto per il prototipo, il che significa che entrambe le menti pensano allo stesso modo o che gli sciocchi non differiscono mai.

Anche se il prototipo funziona abbastanza bene, è molto improbabile che questo renderà la barra di diventare una caratteristica della prossima versione del linguaggio C#. Pochissimi clienti vogliono questa funzionalità, è abbastanza costoso da implementare, abbiamo una lista fino a quando il braccio di caratteristiche più importanti, e ci sono altri modi per fare questo tipo di lavoro cosa senza l'aggiunta di questa complessità al sistema tipo. Questi sono tutti dei "punti contro" che fanno la funzione.

Per esempio, si potrebbe fare un paio di delegati:

struct Ref<T> 
{ 
    private readonly Func<T> getter; 
    private readonly Action<T> setter; 
    public Ref(Func<T> getter, Action<T> setter) 
    { 
     this.getter = getter; 
     this.setter = setter; 
    } 
    public T Value { get { return getter(); } set { setter(value); } } 
} 

var arr = new int[10]; 
var myref = new Ref<int>(()=>arr[1], x=>arr[1]=x); 
myref.Value = 10; 
Console.WriteLine(myref.Value); 

Questo è notevolmente più lento rispetto alla stessa funzione implementata con rendimenti ref, ma il vantaggio è che si può fare un Ref<T> in luoghi dove ref è non legale. Ad esempio, è possibile memorizzare Ref<T> in un campo, che non è possibile eseguire con un metodo di restituzione.

Se si dispone di uno scenario interessante davvero impressionante per questo che bisogno metodi ref-ritorno, avrei amore sentirne parlare. Più scenari del mondo reale abbiamo, più è probabile che tale funzionalità possa essere implementata in un'ipotetica versione futura della lingua.

vedere anche domande relative:

Can I use a reference inside a C# function like C++?

Why doesn't C# support the return of references?

e il mio blog post sull'argomento:

http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/

+0

Ho uno scenario, che dubito possa essere fantastico o avvincente, ma mi capita di imbattermi in un altro: una classe che espone una struttura come una proprietà. Se solo 'Class.Struct.Property = value' potesse essere supportato, sarebbe possibile aggiornare in modo efficiente quel valore. Poiché è necessario utilizzare 'Class.Struct = new Struct {Property = value}' o aggiungere proprietà helper ridondanti a 'Class'. Anche 'Ref ' non risolve questo problema. –

+0

@Rick: questa è un'altra ragione per cui le strutture mutabili sono una pratica peggiore. Se vuoi mutare una parte di una particolare istanza di una struct, la stai trattando come un tipo di riferimento; rendilo un tipo di riferimento in primo luogo. –

+6

Concordo concettualmente, ma le strutture mutevoli che sembrano tipi di riferimento sono essenziali per l'efficienza. Se allocare/liberare un milione di istanze di riferimento fosse una struttura veloce di un milione, non sarebbe un problema! –