2011-10-21 23 views
7

Desidero assegnare un riferimento a un campo membro. Ma io, ovviamente, non capisco questa parte del C# molto bene, perché non sono riuscito :-) Quindi, ecco il mio codice:Impostazione di un riferimento a un campo membro in C#

public class End { 
    public string parameter; 

    public End(ref string parameter) { 
     this.parameter = parameter; 
     this.Init(); 
     Console.WriteLine("Inside: {0}", parameter); 
    } 

    public void Init() { 
     this.parameter = "success"; 
    } 
} 

class MainClass { 
    public static void Main(string[] args) { 
      string s = "failed"; 
     End e = new End(ref s); 
     Console.WriteLine("After: {0}", s); 
    } 
} 

uscita è:

Inside: failed 
After: failed 

Come faccio ad avere "successo" su la console?

Grazie in anticipo, dijxtra

+0

A proposito, è logico che si ottenga lo stesso risultato di output (tuttavia capisco che si sta aspettando che il risultato 'successo' venga stampato) perché entrambe le linee' Console.WriteLine' sono eseguite * dopo * il 'Init () 'metodo. – Otiel

risposta

3

Ci sono davvero due problemi qui.

Uno, come gli altri poster hanno detto, non è possibile rigorosamente fare ciò che si sta cercando di fare (come si può essere in grado di con C e simili). Tuttavia - il comportamento e l'intento sono ancora facilmente realizzabili in C# - devi solo farlo in modo C#.

L'altro problema è il tuo sfortunato tentativo di provare e utilizzare stringhe - che sono, come uno degli altri poster menzionati - immutabili - e per definizione vengono copiate.

Quindi, detto questo, il codice può essere facilmente convertito in questa, che credo non fai quello che vuoi:

public class End 
{ 
    public StringBuilder parameter; 

    public End(StringBuilder parameter) 
    { 
     this.parameter = parameter; 
     this.Init(); 
     Console.WriteLine("Inside: {0}", parameter); 
    } 

    public void Init() 
    { 
     this.parameter.Clear(); 
     this.parameter.Append("success"); 
    } 
} 

class MainClass 
{ 
    public static void Main(string[] args) 
    { 
     StringBuilder s = new StringBuilder("failed"); 
     End e = new End(s); 
     Console.WriteLine("After: {0}", s); 
    } 
} 
+0

Questa soluzione è la più elegante tra quelle proposte qui, grazie :-) – dijxtra

+0

Domande e risposte informative, ma non sono d'accordo, l'uso di 'StringBuilder' in questo modo interrompe il suo scopo semantico ed è probabilmente più costoso. È probabilmente il percorso più breve, LOC-saggio, ma va "contro la grana" del CLR. Il semplice 'MyRef di Eric 'comunica lo scopo in modo più pulito e ha l'ulteriore vantaggio di funzionare per qualsiasi tipo specificato. Molto bella. –

+0

@MarcL. - Sì, sarei d'accordo. Il mio approccio era decisamente veloce e sporco, basato principalmente su ciò che percepivo come la reazione (negativa) alla domanda quando inizialmente pubblicato. – Steve

2

Suona come quello che si sta cercando di fare qui è fare un campo di un riferimento a un'altra posizione di archiviazione. Essenzialmente con un campo ref nello stesso modo in cui si ha un parametro ref. Questo non è possibile in C#.

Uno dei problemi principali di questo è che per essere verificabili, CLR (e C#) devono essere in grado di dimostrare che l'oggetto che contiene il campo non vivrà più a lungo della posizione a cui punta. Questo è in genere impossibile poiché gli oggetti vivono nello heap e un ref può facilmente puntare nello stack. Questi due punti hanno una semantica di durata molto diversa (l'heap in genere è più lungo dello stack) e quindi non è possibile dimostrare che uno ref sia valido.

+1

Puoi farlo catturando la stringa 's s originale in una chiusura? – asawyer

+1

@asawyer: Infatti, anche se questo è solo un modo elegante per dire "allocare una classe che ha un campo di stringa, e quindi memorizzare un riferimento alla classe". Se è quello che vuoi fare, fallo. –

+0

@Eric Questo ha perfettamente senso. Grazie! – asawyer

1

In questa linea:

this.parameter = parameter; 

... si copiare il parametro del metodo per il membro della classe parameter. Quindi, in Init(), si assegna di nuovo il valore "successo" al membro classe membro parameter. Nella tua Console.Writeline, quindi, stai scrivendo il valore del parametro method, "failed", perché non hai mai effettivamente modificato il parametro del metodo .

Quello che stai cercando di fare - il modo in cui stai provando a farlo - non è possibile, credo in C#. Non proverei a passare un string con il modificatore ref.

1

Come risponde JaredPar, non è possibile.

Ma il problema è in parte che la stringa è immutabile. Cambia il tuo parametro in class Basket { public string status; } e il tuo codice funzionerebbe fondamentalmente. Non c'è bisogno della parola chiave ref, basta cambiare parameter.status.

E l'altra opzione è ovviamente Console.WriteLine("After: {0}", e.parameter);. Esegui il wrap in una proprietà (di sola scrittura).

+0

Generalmente non mi piace il suggerimento che abbia qualcosa a che fare con l'immutabilità della stringa, che è abbastanza spesso presente per domande che riguardano assegnazioni di stringhe. La riassegnazione non è una mutazione, di tipo mutabile o meno. Comprenderlo ha qualcosa a che fare con l'immutabilità è una distorsione, non sei d'accordo? (Anche se il suggerimento di incapsulare il valore in una classe è valido.) –

+2

Non ancora questo vecchio cane .... La sua unica è una riassegnazione * perché * le stringhe sono immutabili. – Steve

+0

@Steve, per essere chiari, è necessario * utilizzare * riassegnazione * perché * non è possibile modificare la stringa originale. Ma il mio punto più grande è che l'assegnazione è assegnata, il tipo stesso potrebbe essere mutevole o immutabile e il comportamento di assegnazione 'x = y;' sarebbe lo stesso. Il punto più grande è che la mia lettura della domanda è che il tipo stesso era irrilevante, voleva mantenere un riferimento o un alias alla variabile originale passata. A tal fine, tutte le risposte confermano che non è direttamente possibile ma hanno offerto modi di lavorare all'interno del sistema di tipi per raggiungere l'obiettivo generale. –

14

Come altri hanno fatto notare, non è possibile memorizzare un riferimento a una variabile in un campo in C#, o in effetti, qualsiasi linguaggio CLR.

Naturalmente è possibile catturare un riferimento a un'istanza di classe che contiene una variabile abbastanza facilmente:

sealed class MyRef<T> 
{ 
    public T Value { get; set; } 
} 
public class End 
{ 
    public MyRef<string> parameter; 
    public End(MyRef<string> parameter) 
    { 
    this.parameter = parameter; 
    this.Init(); 
    Console.WriteLine("Inside: {0}", parameter.Value); 
    } 
    public void Init() 
    { 
    this.parameter.Value = "success"; 
    } 
} 
class MainClass 
{ 
    public static void Main() 
    { 
    MyRef<string> s = new MyRef<string>(); 
    s.Value = "failed"; 
    End e = new End(s); 
    Console.WriteLine("After: {0}", s.Value); 
    } 
} 

Easy Peasy.

+1

Dovrò leggere questo due volte. –

Problemi correlati