In C # habe ich immer gedacht, dass nicht-primitive Variablen als Referenz und primitive Werte als Wert übergeben wurden.
Wenn also ein nicht-primitives Objekt an eine Methode übergeben wird, wirkt sich alles, was mit dem Objekt in der Methode gemacht wird, auf das übergebene Objekt aus. (C # 101 Zeug)
Ich habe jedoch festgestellt, dass dies nicht der Fall zu sein scheint, wenn ich ein System.Drawing.Image-Objekt übergebe. Wenn ich ein system.drawing.image-Objekt an eine andere Methode übergebe und ein Bild auf dieses Objekt lade, diese Methode den Gültigkeitsbereich verlässt und zur aufrufenden Methode zurückkehrt, wird dieses Bild nicht auf das ursprüngliche Objekt geladen?
Warum ist das?
Objekte werden überhaupt nicht übergeben. Standardmäßig wird das Argument ausgewertet und dessen Wert als Anfangswert des Parameters der aufgerufenen Methode übergeben. Nun ist der wichtige Punkt, dass der Wert eine Referenz für Referenztypen ist - eine Möglichkeit, zu einem Objekt (oder zu null) zu gelangen. Änderungen an diesem Objekt sind für den Aufrufer sichtbar. Wenn Sie jedoch den Wert des Parameters ändern, um auf ein anderes Objekt zu verweisen, wird nicht angezeigt, wenn Sie den Übergabewert verwenden. Dies ist die Standardeinstellung für alle = Typen.
Wenn Sie eine Referenzübergabe verwenden möchten, verwenden Sie mussout
oder ref
, unabhängig davon, ob der Parametertyp ein Werttyp oder ein Referenztyp ist. In diesem Fall wird die Variable selbst als Referenz übergeben, sodass der Parameter denselben Speicherort wie das Argument verwendet und Änderungen am Parameter selbst vom Aufrufer gesehen werden.
Damit:
public void Foo(Image image)
{
// This change won't be seen by the caller: it's changing the value
// of the parameter.
image = Image.FromStream(...);
}
public void Foo(ref Image image)
{
// This change *will* be seen by the caller: it's changing the value
// of the parameter, but we're using pass by reference
image = Image.FromStream(...);
}
public void Foo(Image image)
{
// This change *will* be seen by the caller: it's changing the data
// within the object that the parameter value refers to.
image.RotateFlip(...);
}
Ich habe einen Artikel, auf den hier viel näher eingegangen wird . Grundsätzlich bedeutet "Referenzübergabe" nicht, was Sie denken, dass es bedeutet.
Ein weiteres Codebeispiel, um dies zu demonstrieren:
void Main()
{
int k = 0;
TestPlain(k);
Console.WriteLine("TestPlain:" + k);
TestRef(ref k);
Console.WriteLine("TestRef:" + k);
string t = "test";
TestObjPlain(t);
Console.WriteLine("TestObjPlain:" +t);
TestObjRef(ref t);
Console.WriteLine("TestObjRef:" + t);
}
public static void TestRef(ref int i)
{
i = 5;
}
public static void TestPlain(int i)
{
i = 5;
}
public static void TestObjRef(ref string s)
{
s = "TestObjRef";
}
public static void TestObjPlain(string s)
{
s = "TestObjPlain";
}
Und die Ausgabe:
TestPlain: 0
TestRef: 5
TestObjPlain: Test
TestObjRef: TestObjRef
Ich denke, es ist klarer, wenn du es so machst. Ich empfehle LinqPad herunterzuladen, um solche Dinge zu testen.
void Main()
{
var Person = new Person(){FirstName = "Egli", LastName = "Becerra"};
//Will update egli
WontUpdate(Person);
Console.WriteLine("WontUpdate");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
UpdateImplicitly(Person);
Console.WriteLine("UpdateImplicitly");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
UpdateExplicitly(ref Person);
Console.WriteLine("UpdateExplicitly");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
}
//Class to test
public class Person{
public string FirstName {get; set;}
public string LastName {get; set;}
public string printName(){
return $"First name: {FirstName} Last name:{LastName}";
}
}
public static void WontUpdate(Person p)
{
//New instance does jack...
var newP = new Person(){FirstName = p.FirstName, LastName = p.LastName};
newP.FirstName = "Favio";
newP.LastName = "Becerra";
}
public static void UpdateImplicitly(Person p)
{
//Passing by reference implicitly
p.FirstName = "Favio";
p.LastName = "Becerra";
}
public static void UpdateExplicitly(ref Person p)
{
//Again passing by reference explicitly (reduntant)
p.FirstName = "Favio";
p.LastName = "Becerra";
}
Und das sollte ausgeben
WontUpdate
Vorname: Egli, Nachname: Becerra
UpdateImplicitly
Vorname: Favio, Nachname: Becerra
UpdateExplicitly
Vorname: Favio, Nachname: Becerra
Wenn Sie das Objekt vom Typ System.Drawing.Image
An eine Methode übergeben, übergeben Sie tatsächlich eine Kopie des Verweises auf dieses Objekt.
Wenn Sie also innerhalb dieser Methode ein neues Bild laden, verwenden Sie eine neue/kopierte Referenz. Sie nehmen keine Änderungen im Original vor.
YourMethod(System.Drawing.Image image)
{
//now this image is a new reference
//if you load a new image
image = new Image()..
//you are not changing the original reference you are just changing the copy of original reference
}
Wie haben Sie das Objekt an die Methode übergeben?
Machst du neu in dieser Methode für Objekt? In diesem Fall müssen Sie ref
in der Methode verwenden.
Der folgende Link gibt Ihnen eine bessere Vorstellung.
http://dotnetstep.blogspot.com/2008/09/passing-reference-type-byval-or-byref.html