2012-10-29 6 views
7

Nel seguente codice, sto cercando di avere un metodo (Work) dalla classe TestClass per modificare i valori di alcune variabili nel programma principale senza doverli restituire. Le variabili vengono passate per riferimento nel costruttore TestClass.C# - passando i parametri per riferimento al costruttore, quindi utilizzandoli dal metodo

class Program 
{ 
    static void Main(string[] args) 
    { 
     int a, b, c, d; 
     a = 5; b = 10; c = 20; d = 25; 
     Console.WriteLine("Main before TestClass: a=" + a + " b=" + b + " c=" + c + " d=" + d); 
     TestClass testObj = new TestClass(ref a,ref b,ref c,ref d); 
     testObj.Work(); 
     Console.WriteLine("Main after TestClass: a=" + a + " b=" + b + " c=" + c + " d=" + d); 
     Console.ReadLine(); 
    } 
} 

public class TestClass 
{ 
    int _a, _b, _c, _d; 
    public TestClass(ref int a, ref int b, ref int c, ref int d) 
    { 
     _a = a; _b = b; _c = c; _d = d; 
    } 

    public void Work() 
    { 
     Console.WriteLine("Work before changing: a=" + _a + " b=" + _b + " c=" + _c + " d=" + _d); 
     _a = 0; _b = 1; _c = 2; _d = 3; 
     Console.WriteLine("Work after changing: a=" + _a + " b=" + _b + " c=" + _c + " d=" + _d); 
    } 
} 

Tuttavia, questo codice restituisce:

Main before TestClass: a=5 b=10 c=20 d=25 
Work before changing: a=5 b=10 c=20 d=25 
Work after changing: a=0 b=1 c=2 d=3 
Main after TestClass: a=5 b=10 c=20 d=25 

C'è un modo per avere il metodo di modificare i valori delle variabili nel programma principale? Grazie!

+2

Dovresti memorizzare * riferimenti * in '_a', ecc., Ma li hai appena dichiarati come' int's. A quanto pare, il CLR non supporta questo concetto: tu * puoi * avere variabili locali che sono riferimenti, ma non campi. [Ma C# non ti permette nemmeno di dichiarare tali variabili locali] (http://blogs.msdn.com/b/ericlippert/archive/2011/06/23/ref-returns-and-ref-locals.aspx). –

risposta

3

Si sarebbe meglio creare i propri involucri oltre Int32 in modo che le modifiche si riflettano, perché una volta che i valori vengono assegnati ai campi della classe, non sono più riferimenti, ma piuttosto diverse istanze di Int32 . Considera il seguente codice:

class Integer { 
    public int Value; 

    public Integer(int value) { 
     Value = value; 
    } 

    public override string ToString() { 
     return Value.ToString(); 
    } 
} 

class TestClass { 
    Integer _a, _b, _c, _d; 

    public TestClass(Integer a, Integer b, Integer c, Integer d) { 
     _a = a; 
     _b = b; 
     _c = c; 
     _d = d; 
    } 

    public void Work() { 
     _a.Value = 111; 
     _b.Value = 222; 
     _c.Value = 333; 
     _d.Value = 444; 
    } 
} 

Quindi ora hai un intero: una classe wrapper su Int32. L'utilizzo vi porterà i risultati:

Integer a = new Integer(0), b = new Integer(0), c = new Integer(0), d = new Integer(0); 
Console.WriteLine("a: {0}, b: {1}, c: {2}, d: {3}", a, b, c, d); 
new TestClass(a, b, c, d).Work(); 
Console.WriteLine("a: {0}, b: {1}, c: {2}, d: {3}", a, b, c, d); 

l'output è:

a: 0, b: 0, c: 0, d: 0 
a: 111, b: 222, c: 333, d: 444 

Si può anche essere utile per leggere di più su classi e struct in C#, per esempio http://msdn.microsoft.com/en-us/library/ms173109.aspx. (Int32 è una struttura, mentre nel tuo caso probabilmente avete bisogno di una classe)

+0

Grazie, ha funzionato! – panostra

3

Non possibile. Non è possibile memorizzare un riferimento a un int come membro e solo int a è una copia: le modifiche apportate alla copia non cambiano l'originale, come si è visto.

È possibile includere lo int all'interno di un corso. È possibile memorizzare un riferimento alla classe e operare su di esso allora.

public class IntWrapper 
{ 
    public IntWrapper(int val = 0) { Value = val; } 
    public int Value { get; set; } 
} 

static void Main(string[] args) 
{ 
    IntWrapper a = new IntWrapper(5); 
    TestClass testObj = new TestClass(a); 
    testObj.Work(); 
} 

public class TestClass 
{ 
    IntWrapper _a; 
    public TestClass(IntWrapper a) 
    { 
     _a = a; 
    } 

    public void Work() 
    { 
     Console.WriteLine("Work before changing: a=" + _a.Value); 
     _a.Value = 0; 
     Console.WriteLine("Work after changing: a=" + _a.Value); 
    } 
} 
2

Che cosa si sta cercando di fare non può essere fatto in quanto non è stato progettato per essere utilizzato in questo modo. Dovresti inserire i parametri direttamente nel metodo Work, ad es.

testObj.Work(ref a, ref b, ref c, ref d); 
2

Questo comportamento è causato da:

int _a, _b, _c, _d; 
public TestClass(ref int a, ref int b, ref int c, ref int d) 
{ 
    _a = a; _b = b; _c = c; _d = d; 
} 

int è una struttura (un tipo di valore). Ciò significa che NON stai passando il riferimento (o il puntatore) ai campi come ci si potrebbe aspettare, anche se si utilizza la parola chiave ref. Quello che stai facendo invece è assegnare ai campi i valori interi dati come input, niente di più.
per ottenere ciò che ci si aspetta è necessario utilizzare un tipo di riferimento (avvolgere il vostro intero in una classe) o fare riferimento i vostri numeri interi (tramite la parola chiave ref) nel metodo in cui è effettivamente cambiare i loro valori:

public void Work(ref int a, ref int b, ref int c, ref int d) 
{ 
    Console.WriteLine("Work before changing: a=" + a + " b=" + b + " c=" + c + " d=" + _d); 
    a = 0; b = 1; c = 2; d = 3; 
    Console.WriteLine("Work after changing: a=" + a + " b=" + b + " c=" + c + " d=" + _d); 
} 

l'effetto del passaggio per riferimento è che qualsiasi modifica al parametro nel metodo chiamato si riflette nella metodo chiamata.

Per ulteriori informazioni sulla parola chiave ref, dare un'occhiata a: ref (C# Reference).

Problemi correlati