Warum # c Objekte einmal wie von Wert übergeben verhalten und wie einmal durch Verweis übergeben?

stimmen
1

Ich verstehe nicht , eine Sache , über Parameter an Methoden in c # übergeben. Von dem, was ich Objekte in c # sehen manchmal verhalten sich wie die durch Bezugnahme und einmal bestanden, als ob sie von Wert übergeben wurden. In diesem Code gebe ich zu method()einem von Referenz- und einmal von Wert. Beide ausführen , wie erwartet. Aber wenn ich erstellt Update()und ein Objekt nach Wert übergeben Ich sehe es benimmt sich wie es Original - Objekt aktualisiert.

Warum aktualisiere ich Original - Objekt mit , Update(myString input)aber nicht aktualisieren es mit method(myString input)?

Das ist unlogisch!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClassPassing
{
class Program
{
    static void Main(string[] args)
    {
        myString zmienna = new myString();

        Update(zmienna);
        Console.WriteLine(zmienna.stringValue);
        Console.WriteLine(zmienna.stringValue2);
        Console.ReadLine();

        zmienna.stringValue = This has run in main;
        zmienna.stringValue2 = This is a help string;

        method(zmienna);
        Console.WriteLine(zmienna.stringValue);
        Console.WriteLine(zmienna.stringValue2);
        Console.ReadLine();

        method(ref zmienna);
        Console.WriteLine(zmienna.stringValue);
        Console.WriteLine(zmienna.stringValue2);

        Console.ReadLine();
    }

    static void method(myString input)
    {
        input = new myString();
    }

    static void method(ref myString input)
    {
        input = new myString();
    }

    static void Update(myString input)
    {
        input.stringValue2 = This has run in update method;
    }
}

public class myString
{
    public string stringValue { get; set; }
    public string stringValue2 { get; set; }

    public myString() { stringValue = This has been just constructed;   this.stringValue2 = This has been just constructed; }
}

} `

Veröffentlicht am 14/11/2013 um 12:31
vom benutzer
In anderen Sprachen...                            


4 antworten

stimmen
4

Sie haben Ihren Code zu verstehen:

static void method(myString input)
{
    input = new myString();
}

Hier passieren Sie Verweis auf Objekt nach Wert

static void method(ref myString input)
{
    input = new myString();
}

Hier passieren Sie Verweis auf Objekt durch Verweis

static void Update(myString input)
{
    input.stringValue2 = "This has run in update method";
}

Auch hier kommt man Bezug von Wert zum Objekt

Jetzt:

  1. Wenn Sie Objektreferenz als Wert übergeben , können Sie den Inhalt des Objekts ändern, aber Sie können nicht die Referenz selbst (zu einem anderen Objekt zuweisen es) ändern.
  2. Wenn Sie Objektverweis durch Verweis übergeben , können Sie den Inhalt des Objekts ändern beide und Sie können die Referenz selbst (zuweisen es auf ein anderes Objekt) ändern.

Die wirklichen vorbei Wert in C # tritt nur bei einfach (int, float, etc.) Typen und bei structs:

class Program 
{
    public struct MyStruct
    {
        public int i;
    }

    public class MyClass 
    {
        public int i;
    }

    public static void Modify(MyStruct s) 
    {
        s.i = 99;
    }

    public static void Modify(MyClass c) 
    {
        c.i = 99;
    }

    public static void Main(string[] args) 
    {
        MyStruct myStruct = new MyStruct();
        myStruct.i = 20;
        MyClass myClass = new MyClass();
        myClass.i = 20;

        Modify(myStruct);
        Modify(myClass);

        Console.WriteLine("MyStruct.i = {0}", myStruct.i);
        Console.WriteLine("MyClass.i = {0}", myClass.i);

        Console.ReadKey();
    }
}

Ergebnis:

MyStruct.i = 20
MyClass.i = 99  

In diesem Fall MyStructblieb ‚s - Wert unverändert, weil es eine Funktion übergeben wurde von Wert . Auf der anderen Seite, MyClass‚s - Instanz übergeben wurde durch Bezugnahme und deshalb sein Wert verändert.

Beantwortet am 14/11/2013 um 12:33
quelle vom benutzer

stimmen
4

Objekte werden nicht alle bestanden.

Für Ausdrücke eines Referenztyps (Klassen, Schnittstellen usw.) Referenzen übergeben werden - nach Wert standardmäßig, aber die Variablen als Referenz übergeben , wenn Sie verwenden ref.

Es ist wichtig zu verstehen , dass der Wert zmiennanicht ein Objekt ist - es ist eine Referenz ist. Sobald Sie haben die sortiert, wird der Rest einfach. Es ist nicht nur für die Parameterübergabe entweder - es ist alles . Beispielsweise:

StringBuilder x = new StringBuilder();
StringBuilder y = x;
y.Append("Foo");
Console.WriteLine(x); // Prints Foo

Hier werden die Werte von xund ybeziehen sich auf das gleiche Objekt - es ist wie mit zwei Papierstücke, von denen jeder auf die gleiche Adresse hat. Also , wenn jemand das Haus besucht , indem die auf geschriebene Adresse zu lesen xund malt die Haustür rot, dann jemand anderes Besuche das gleiche Haus , indem die auf schriftliche Adresse zu lesen y, werden diese zweite Person eine rote Haustür sehen.

Sehen Sie meinen Artikel über Referenz- und Werttypen und Parameter übergeben , um weitere Informationen.

Beantwortet am 14/11/2013 um 12:34
quelle vom benutzer

stimmen
0

Es kann mehrere Fragen sein, hier zu beantworten, aber in Bezug auf Ihre letzten:

"Why do I update original object with Update(myString input) but do not update it with method(myString input)?"

Hier werden Sie eine neue Instanz der Erstellung der myStringKlasse und nicht die Bezugnahme auf das Original , das auf die Methode als Parameter übergeben wurde. Also , wenn Sie den Wert ändern , input.stringValue2innerhalb der Methode, werden Sie den Wert verlieren , sobald Sie die Methode verlassen.

static void method(myString input)
{
    input = new myString();
}

Aber hier Sie verweisen die ursprüngliche Instanz an sie übergeben. Wenn Sie diese Methode verlassen, das Original myStringwird Instanz den Wert behalten stringValue2.

static void Update(myString input)
{
    input.stringValue2 = "This has run in update method";
}
Beantwortet am 14/11/2013 um 12:34
quelle vom benutzer

stimmen
0

Stellen Sie sich vor Computerspeicher als eine Reihe von Boxen, und dass Sie sie Namen Etiketten geben.

myString zmienna = new myString();

Hier ordnen Sie eine Box mit einer Instanz myStringin ihm, und haben ein Etikett zmiennaauf sie zeigen. Dann:

static void method(myString input)
{
    input = new myString();
}

Bei diesem Verfahren inputist eine andere Markierung ein. Der Aufruf der Methode machen Sie zuerst das Etikett inputauf die gleiche Box, mit der ursprünglichen Instanz. Jedoch in den körpereigenen Verfahren Sie ein anderes Feld zuweisen und ändern Sie das Etikett input zu diesem neuen Feld zu zeigen. Es wird nichts mit dem ersten Feld gemacht, und nichts wird mit getan zmiennaLabel.

static void method(ref myString input)
{
    input = new myString();
}

Hier wegen des refKeyword bist du nicht nur vorbei , den Aufenthaltsort der ersten „Memory Box“, aber Sie geben das tatsächliche Etikett. So dass diese Methode des Körper aktualisiert Ihr Etikett zmiennaauf ein neu angelegtes Feld zu zeigen, mit einer zweiten Instanz myString. Das erste Feld wird vergessen, da keine Etiketten darauf zeigen.

static void Update(myString input)
{
    input.stringValue2 = "This has run in update method";
}

In diesem Fall übergeben Sie die Adresse des ersten Kastens, in genau der gleichen Weise wie in dem ersten Verfahren. So haben Sie zwei labes: zmiennaund input- beide zeigen auf das gleiche Feld. Daher input.stringValue2greift auf das Feld stringValue2in der gleichen Box , die von gerichtet ist zmienna.

Ein genauer Begriff tatsächlich verwendeter Referenz statt Label Begriff ich in dieser Erklärung verwenden. Ich finde irgendwie , dass viele Menschen finden es einfacher , auf diese Weise zu verstehen :)

Beantwortet am 14/11/2013 um 12:37
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more