Zum Inhalt springen

[C#] Objekte werden in Schleife referenziert


Empfohlene Beiträge

Geschrieben (bearbeitet)

Hi allerseits,

folgendes Ereigniss iritiert mich und ich hoffe ihr könnt mir das näher erläutern.

Ich habe eine Liste von objekten, welche ich durchschleife.

Deren Elemente lasse ich auf diverse Konstelationen prüfen.

Sofern diese den Anforderungen entsprechen, werden Sie zur Bearbeitung an eine weitere Klasse weitergegeben (ohne ref etc.).

Wenn der Dialog dann zweckmäßig beendet wird, wird das veränderte Objekt einer neuen Liste hinzugefügt. Jedoch verwirt mich das das ursprungsobjekt der Ursprungsliste ebenfalls den geänderten Wert innehält.


                    foreach (ppt.SlideObject item in cSlide.Objects)

                    {

                        if (item.UniqueID == (int)dataGridView1.SelectedRows[0].Cells[1].Value && (Core.MsoShapeType)item.Type == Microsoft.Office.Core.MsoShapeType.msoGroup) {

                            for (int ival =0;ival<=item.Define.GroupShapeCollection.Container.Count - 1;ival++)

                            {

                                if (item.Define.GroupShapeCollection.Container[ival].Define.GroupLink != null && item.Define.GroupShapeCollection.Container[ival].Define.GroupLink.GroupUniqueID == (int)dataGridView1.SelectedRows[0].Cells[1].Value && item.Define.GroupShapeCollection.Container[ival].ID == (int)dataGridView1.SelectedRows[0].Cells[0].Value)

                                {

                                    el.obj = item.Define.GroupShapeCollection.Container[ival];

                                    if (el.ShowDialog() == DialogResult.OK && el.hChanged)

                                    {

                                        ppt.RevSlideObject xobj = new pptdispatcher.ppt.RevSlideObject(el.obj);

                                        xobj.TempName = "TempRev" + (refobjects.Count + 1).ToString() + " " + xobj.Name;

                                        xobj.VirtualID = "v" + (virtualidcounter++).ToString();

                                        xobj.ID = id;

                                        refobjects.Add(xobj);

                                        object[] row = new object[4];

                                        row[0] = xobj.VirtualID;

                                        row[1] = false;

                                        row[2] = xobj.TempName;

                                        row[3] = "-----------";

                                        dataGridView2.Rows.Add(row);

                                    }

                                    break;

                                }


                            }

                            break;

                        }

                    }

Kleineres Beispiel anhand von PseudoCode:

String Stringliste

Für jedes Stringelement in Stringliste

BEGIN

String lokalerstring = Stringelement

WENN lokalerstring gleich "Test123"

BEGIN

lokalerstring = "Fertig"

//Wird dieser Wert verändert wird auch das Stringelement in der Liste entsprechend verändert.

//Meine Frage also: Warum wird hier referenziert und wie kann ich das verhindert?

END

END

lg

Gateway

Bearbeitet von Gateway_man
Geschrieben

Warum ist das dann bei folgendem kleinen vb beispiel nicht so?


        Dim list As List(Of Object) = New List(Of Object)

        list.Add("test1")

        list.Add("test2")

        For Each item As Object In list

            Dim localstring as Object = item

            If localstring = "test1" Then

                localstring = "x1"

            End If

        Next

Der Wert des ersten Elements in der Liste bekommt nicht den wert x1. Das ist genau die selbe konstelation (nur vereinfacht) wie in meiner C Sharp Routine. der wert des localstrings wird auf x1 gesetzt werden der Wert des Objects Item weiterhin "test1" lautet.

lg

Gateway

Geschrieben

Da stimmt was nicht. Denn wenn ich mit C# selbiges Beispiel durchgehe erhalte ich genau das selbe verhalten wie bei vb.net.

List<object> list = new List<object>();

list.Add("test1");

list.Add("test2");

foreach (object item in list)

{

object localstring = item;

if (localstring == "test1")

{

localstring = "x1";

}

}

Und zwar exakt das selbe. Sprich es scheint wohl doch nicht referenziert zu werden in diesem Fall. Das würde mich auch wundern da mir so etwas schon früher aufgefallen wäre, da ich nicht erst seit gestern mit C# arbeite. Umso mehr wundert mich das Ereigniss im ersten Post, da ich wie gesagt das selbe Schema verfolge.

lg

Gateway

Geschrieben

hi,

sry steh hier echt aufm Schlau :old. Weder übergebe ich das Objekt einer Funktion mit einem ref Schlüsselwort oder definiere dieses in einer anderen Funktion neu.

Gibts keinen Befehl mit dem ich ein Objekt gänzlich kopiere?

Ich versteh grad nur Bahnhof.

Das es bei Übergabeparametern prinzipiell zwei möglichkeiten gibt war mir schon bewusst. Aber das betrifft mich doch nicht da ich nichtmal einene Funktion aufrufe. Daher versteh ich jetzt den Zusammenhang mit der msdn Seite nicht ganz.

Ich hab das mal eingegrenzt und den Wert Manuel geändert noch in der Foreach schleife mit dem selben irritierenden Ergebniss.


                            foreach (ppt.SlideObject subitem in item.Define.GroupShapeCollection.Container)

                            {

                                if (subitem.Define.GroupLink != null && subitem.Define.GroupLink.GroupUniqueID == (int)dataGridView1.SelectedRows[0].Cells[1].Value && subitem.ID == (int)dataGridView1.SelectedRows[0].Cells[0].Value)

                                {

                                    //System.Runtime.InteropServices.Marshal.cop

                                    ppt.SlideObject cobj = subitem;

                                    cobj.Define.TxTFrame.Value = "test";

                                    //Auch hier wird ebenfalls der Wert des subitems auf test!

                                    //Ich versteh nurnoch Bahnhof

                                    break;

                                }


                            }

Geschrieben
Aber das betrifft mich doch nicht da ich nichtmal einene Funktion aufrufe. Daher versteh ich jetzt den Zusammenhang mit der msdn Seite nicht ganz.

Da du oben schriebst das du es ohne ref übergibst bin ich davon ausgegangen das du es einer Methode einer anderen Klasse übergibst.

Das Prinzip ist aber trotzdem das Selbe.


namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
A a = new A();
a.str = "Hello";

B b = new B();
b.value = a;
b.value.str = "World";
Console.WriteLine("{0} {1}!", a.str, b.value.str);
}
}

class A
{
public string str;
}

class B
{
public A value;
}
}
[/PHP]

Gibt [i]World World![/i] aus weil hier

b.value = a;

b.value eine Referenz auf a zugewiesen wird da Klassen immer Referenzdatentypen sind.

Wenn man das nicht will muss man das Objekt kopieren. Eine Möglichkeit dazu wäre Serialisieren und wieder Deserialisieren oder zum Beispiel IClonable zu implementieren:

[PHP]
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
A a = new A();
a.str = "Hello";

B b = new B();
b.value = a.Clone() as A;
b.value.str = "World";
Console.WriteLine("{0} {1}!", a.str, b.value.str);
}
}

class A : ICloneable
{
public string str;

#region ICloneable Members

public object Clone()
{
return this.MemberwiseClone();
}

#endregion
}

class B
{
public A value;
}
}

Wenn eine flache Kopie nicht ausreichen sollte muss man dann halt in der Clone Methode die entsprechenden Member manuell kopieren.

Geschrieben

So hat sich nun herrausgestellt das sich diese Klasse sich nicht "Klonnen" lässt :(.

Ist mir bissher nie so richtig aufgefallen, aber mir hat diese Seite sehr geholfen.

Ich muss sagen ich kann diese engen Regeln des .NET nicht ganz nachvollziehn. In anderen Sprachen ist man dahingehend doch etwas freier.

Geschrieben

Was hier Verwirrung stiftet ist der Unterschied zwischen call by reference und call by value, welches man in anderen Sprachen kennt und dem signifikanten Unterschied zwischen Werttypen und Referenztypen in C#.

Was Du im Sinn hast ist erstere Unterscheidung.

In der Regel erfolgt bei C# eine Übergabe als call by value.

Das hat aber folgenden Effekt:

Wird ein Werttyp übergeben wird innerhalb der Funktion mit einer Kopie der Werttypen gearbeitet. Das Verhalten, was man im Grunde auch von call by value erwartet. Wird ein Referenztyp übergeben, so wird auch dieser "Wert" kopiert - also reguläres call by value-Verhalten.

Der Haken an der Sache ist, dass es sich eben lediglich um die Kopie der Referenz und nicht um eine Kopie des referenzierten Objekts handelt.

C# verhält sich ganz konsistent, aber für den unbedarften Nutzer kontraintuitiv.

Rapid Application Development: Parameter passing in C#

erklärt die Zusammenhänge sehr gut.

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...