Przekazywanie obiektów i lista obiektów przez odniesienie w C#

Mam delegata, który modyfikuje obiekt. Przekazuję obiekt delegatowi z metody wywołującej, jednak metoda wywołująca nie wychwytuje tych zmian. Ten sam kod działa, jeśli przekażę List jako obiekt.

Myślałem, że wszystkie obiekty są przekazywane przez referencję, więc wszelkie modyfikacje będą odzwierciedlone w wywołaniu metody. Zgadza się?

Mogę zmodyfikować mój kod, aby przekazać ref obiekt delegatowi. Ale zastanawiam się, dlaczego jest to konieczne. Lub jest to?

public class Binder
{
    protected delegate int MyBinder<T>(object reader, T myObject);

    public void BindIt<T>(object reader, T myObject)
    {
        //m_binders is a hashtable of binder objects
        MyBinder<T> binder = m_binders["test"] as MyBinder<T>;
        int i = binder(reader, myObject);
    }
}

public class MyObjectBinder
{
    public MyObjectBinder()
    {
        m_delegates["test"] = new MyBinder<MyObject>(BindMyObject);
    }

    private int BindMyObject(object reader, MyObject obj)
    {
        obj = new MyObject
        {
            //update properties
        };
        return 1;
    }
}

///calling method in some other class
public void CallingMethod()
{
    MyObject obj = new MyObject();

    MyObjectBinder binder = new MyObjectBinder();
    binder.BindIt(myReader, obj); //don't worry about myReader

    //obj should show reflected changes
}

Update:

Przekazuję teraz obiekty przez ref do delegata, tworząc nowy obiekt wewnątrz BindMyObject.

protected delegate int MyBinder<T>(object reader, ref T myObject);
Author: DavidRR, 2010-06-14

1 answers

Obiekty nie są przekazywane przez odniesienie. Obiekty w ogóle nie są przekazywane.

Domyślnie wartość argumentu jest przekazywana przez value - niezależnie od tego, czy jest to wartość typu value, czy Referencja. Jeśli obiekt zostanie zmodyfikowany przez to odniesienie, zmiana ta będzie widoczna również dla kodu wywołującego.

W kodzie, który pokazałeś, nie było powodu, by używać ref. Słowo kluczowe ref jest używane, gdy chcesz, aby metoda zmieniła wartość parametru (np. aby odnosiło się całkowicie do innego obiektu) i aby zmiana ta była widoczna dla wywołującego.

Teraz w kodzie, który pokazałeś (oryginalnie) masz tylko:

private int BindMyObject(object reader, MyObject obj)
{
    //make changes to obj in here
}

Masz na myśli taki kod:

private int BindMyObject(object reader, MyObject obj)
{
    obj = new MyObject();
}

Lub kod taki:

private int BindMyObject(object reader, MyObject obj)
{
    obj.SomeProperty = differentValue;
}

? Jeśli jest to drugie, to nie potrzebujesz ref. Jeśli jest to pierwszy, to robisz potrzebujesz ref, ponieważ zmieniasz sam parametr, a nie wprowadzasz zmian do obiektu, do którego odnosi się wartość. W rzeczywistości, jeśli po prostu ustawiasz wartość obj bez czytania jej, powinieneś użyć out zamiast ref.

Jeśli możesz pokazać krótki, ale kompletny program, który demonstruje twój problem, o wiele łatwiej będzie wyjaśnić, o co chodzi.

Trudno jest zrobić ten temat w zaledwie kilku akapitach-więc mam cały artykuł o tym , który, miejmy nadzieję, uczyni rzeczy bardziej oczywistymi.

 103
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-09 20:37:08