2012-10-29 9 views
7

W poniższym kodzie próbuję mieć metodę (Praca) z klasy TestClass, zmieniając wartości niektórych zmiennych w programie głównym bez konieczności ich zwracania. Zmienne są przekazywane przez odniesienie w konstruktorze TestClass.C# - przekazywanie parametrów przez odwołanie do konstruktora, a następnie użycie ich z metody

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); 
    } 
} 

Jednak kod ten zwraca:

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 

Czy istnieje jakiś sposób, aby mieć metoda zmiany wartości zmiennych w programie głównym? Dziękujemy!

+2

Będziesz musiał przechowywać * referencje * w '_a', etc, ale właśnie zadeklarowałeś je jako' int's. Jak się okazuje, środowisko CLR nie obsługuje tej koncepcji - możesz * mieć * zmienne lokalne, które są referencjami, ale nie pola. [Ale C# nie pozwala nawet zadeklarować takich zmiennych lokalnych] (http://blogs.msdn.com/b/ericlippert/archive/2011/06/23/ref-returns-and-ref-locals.aspx). –

Odpowiedz

3

Użytkownik będzie lepiej tworzenia własnych obwolut ponad Int32 w celu zmiany mają być widoczne, ponieważ po wartości są przypisane do pól klasy, już nie są referencje, ale raczej różne instancje Int32 . Rozważmy następujący kod:

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; 
    } 
} 

Masz teraz Integer - klasę otoki nad Int32. Wykorzystanie przyniesie Ci wyniki:

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); 

wyjście jest:

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

Można również stwierdzić, że warto przeczytać więcej na temat klas i kodowanym w C#, na przykład http://msdn.microsoft.com/en-us/library/ms173109.aspx. (Int32 jest struct, podczas gdy w twoim przypadku prawdopodobnie trzeba klasę)

+0

Dziękuję, zadziałało! – panostra

3

Niemożliwe. Nie można zapisać odniesienia do numeru int jako członka, a tylko int a jest kopią - zmiany w kopii nie zmieniają oryginału, jak widzieliście.

Możesz zawinąć to int w klasie. Możesz zapisać odniesienie do klasy i działać na nim wtedy.

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

To, co próbujesz zrobić, nie może zostać wykonane, ponieważ nie zostało zaprojektowane do użycia w ten sposób. Musiałbyś mieć parametry bezpośrednio w metodzie Work zamiast np.

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

Takie zachowanie jest spowodowane przez:

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 jest strukturą (typ wartości). Oznacza to, że NIE przekazujesz odniesienia (lub wskaźnika) do pól, jak można się spodziewać, nawet jeśli użyjesz słowa kluczowego ref. Zamiast tego przypisujesz do pól wartości całkowite podane jako dane wejściowe, nic więcej.
Aby osiągnąć co czekasz trzeba użyć typu referencyjnego (owinąć całkowitą w klasie) lub odwołać swoje całkowite (przez ref słowa kluczowego) w sposobie, w którym faktycznie zmieniają swoje wartości:

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); 
} 

efekt przechodzi odniesienia jest to, że każda zmiana parametru w metodzie nazywa znajduje odzwierciedlenie w wywołującego metody.

Aby lepiej zrozumieć słowa kluczowego ref nadać wygląd: ref (C# Reference).

Powiązane problemy