WinFuture-Forum.de: [gelöst] Deserialisiertes Objekt nach Zuweisung == NULL - WinFuture-Forum.de

Zum Inhalt wechseln

Nachrichten zum Thema: Entwicklung
Seite 1 von 1

[gelöst] Deserialisiertes Objekt nach Zuweisung == NULL Referenz wird nur mit ref-Schlüsselwort korrekt bearbeitet?

#1 Mitglied ist offline   nobido 

  • Gruppe: aktive Mitglieder
  • Beiträge: 157
  • Beigetreten: 20. April 07
  • Reputation: 6

geschrieben 04. Februar 2013 - 15:09

Hallo Leute,

ich bin seit an paar Tagen am grübeln. Mir ist da nämlich etwas seltsames, wie mir scheint, passiert. Ich poste vorweg einfach mal den Quell-Code (sorry wenn's bissl viel sein sollte).

Dies der Quellcode aus der Controller.cs

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

using EproxModell;

namespace EproxController
{
    public enum DataSourceType
    {
        None =  0,
        PDB  = 10,
        ACC  = 20,
        SQL  = 30
    }

    [Serializable]
    public class ProgramOptions
    {
        readonly bool isInitiated;
        public bool IsInitiated
        { get { return isInitiated; }} 

        DataSourceType dataSourceType = DataSourceType.None;
        public DataSourceType DataSourceType
        {
            get { return dataSourceType; }
            set { dataSourceType = value; }
        }

        string pathToSqlServer = string.Empty;
        public string PathToSqlServer
        { get { return pathToSqlServer; }}

        string fileName = string.Empty;
        public string FileName
        { get { return fileName; }}

        string userName = string.Empty;
        public string UserName
        { get { return userName; }}

        string passWord = string.Empty;
        public string PassWord
        { get { return passWord; }}

        private ProgramOptions()
        { }

        public ProgramOptions(DataSourceType _dataSourceType, string _fileName = "")
        {
            this.dataSourceType = _dataSourceType;
            this.fileName = _fileName;
            this.isInitiated = true;
        }
    }

    public class CEproxController
    {
        #region Singleton-Instanz

        private static volatile CEproxController instance;
        private static object syncRoot = new Object();
        public ProgramOptions programOptions;
        public bool HasConfig { get; set; }
        
        public static CEproxController Instance
        {
            get 
            {
                if (instance == null) 
                {
                    lock (syncRoot) 
                    {
                        if (instance == null)
                        { instance = new CEproxController(); }
                    }
                }
                //
                return instance;
            }
        }
        #endregion

        DataSetEproxModel ds;

        private CEproxController()
        {
            ds = new DataSetEproxModel();
            Persistent.ReadOptions(ref this.programOptions);
            this.HasConfig = true;
            //Persistent.CreateDefaultOptionsFile();
        }
    }
}



Und hier der Code der Persistent.cs

using System;
using System.IO;
using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace EproxController
{
    static class Persistent
    {
        public static void ReadOptions(ref ProgramOptions _programOptions)
        {
            FileStream fs = new FileStream("options.ini", FileMode.OpenOrCreate, FileAccess.ReadWrite);
            BinaryFormatter bf = new BinaryFormatter();

            try
            {
                _programOptions = (ProgramOptions)bf.Deserialize(fs);
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                fs.Flush();
                fs.Close();
            }
        }

        public static void CreateDefaultOptionsFile()
        { }
    }
}



Beide Quellcodes sind im selben Projekt. Ich habe halt nur zwei Dateien angelegt um die eigentlichen Funktionen der Controller-Klasse frei von Dateioperationen zu halten.

So, nun zu dem Seltsame. Von dem ich sprach es wäre mir passiert.
Wenn ich im Konstruktor der Controller-Klasse die Methode ReadOptions der Klasse Persistent aufrufe passiert fogendes (oder sollte):

Die Referenz programOptions, die ich an die Methode ReadOptions in Persistent übergebe, wird wegen des ref-Schlüsselwort als Referenz übergeben. Sozusagen wird eine Referenz auf jene Referenz(Variable?) übergeben, die ein Objekt vom Typ ProgramOptions referenziert bzw. referenzieren kann. Denn, so mein Wissensstand, wenn die Variable nur deklariert wird, dann zeigt sie auf nichts/kein Objekt. Sondern ist erstmal nur sowas wie ein Zeiger, der auf nichts (NULL) oder ein entsprechendes Objekt (ProgramOptions in diesem Fall) zeigt/zeigen kann.

Weiterhin glaube ich gelernt zu haben dass Objekt-Referenzen, wie in diesem fall programOptions (vom Typ ProgramOptions), wenn sie denn an Methoden übergeben werden als Referenz übergeben werden. Als Referenz, die auf ein entsprechendes erzeugtes Objekt zeigt.
Sollte die Zuweisung eines (deserialisierten) Objekt an eine entsprechende Referenz der aufrufenden Klasse dann nicht auch ohne das ref-Schlüsselwort möglich sein?

Oder, um es kurz zu machen: Warum funktioniert mein Code nicht, wenn ich das ref-Schlüsselwort in der Methode ReadOptions und im entsprechenden Methodenaufruf weglasse?

Es funktioniert da zwar auch was... innerhalb der ReadOptions-Methode ist die Variable _programOptions nach der Zuweisung des deserialisierten Objekts mit entsprechenden Daten gefüllt. Wenn der Code allerdings in der Controller-Klasse zurück ist, dann ist die dort im Methodenaufruf übergebe Veriable == NULL.

Aber das entspricht, so irgendwie, gar nicht meinem Verständnis vom handling von Objekt-Variablen. Meiner Meinung nach sollte das auch ohne ref-Schlüsselwort laufen.

Was überseh ich?

Gruß
Joey

Dieser Beitrag wurde von nobido bearbeitet: 17. Februar 2013 - 06:24

0

Anzeige

#2 Mitglied ist offline   prunkster 

  • Gruppe: aktive Mitglieder
  • Beiträge: 264
  • Beigetreten: 22. Mai 08
  • Reputation: 3

geschrieben 14. Februar 2013 - 20:33

Hi nobido,

schau mal in diesem MSDN-Artikel ("Example 4: Passing Reference Types by Value" und "Example 5: Passing Reference Types by Reference") nach, das sollte das Phänomen klären...

greetz,
prunkster
Eingefügtes Bild <--- Workstation@Home

My Blog: hier
1

#3 Mitglied ist offline   nobido 

  • Gruppe: aktive Mitglieder
  • Beiträge: 157
  • Beigetreten: 20. April 07
  • Reputation: 6

geschrieben 16. Februar 2013 - 10:41

Hiho prunkbustr

danke für die Antwort.

Bin mittlerweile mitte der Woche auch fündig geworden in einer alten .NET-PRO-Ausgabe (4/2011, S.20). Der Inhalt in Kürze:

Werte werden stadardmäßig byValue übergeben. Referenzen wider Erwarten eben nicht als Referenz, sondern auch byValue. Also: Die Referenz/der Wert der Referenz an sich - in meinem Fall this.ProgramOptions.
Die aufgerufene Methode arbeitet dann mit einer Lokalen Kopie dieser Referenz. Dadurch ist es (zwar) möglich Änderungen an den Eigenschaften des Objekt vorzunehmen, auf welches die Referenz zeigt (bzw. beide Referenzen zeigen). Allerdings kann die Referenz selbst, in meinem Fall die Referenz this.ProgramOptions in der aufgerufenen Methode nicht geändert werden. Die Zuweisung eines Objekt innerhalb der aufgerufenen Methode an die (lokale Kopie der) Referenz hat nur innerhalb der Methode Auswirkungen.

Weswegen bei mir this.ProgramOptions nach dem Methodenaufruf auch weiterhin NULL war. So wie anfangs auch deklariert.


Trotzdem danke nochmal für die Antwort. Ich hatte schon die Befürchtung ich laufe da mit einem Anfängerproblem auf, dem sich niemand widmen mag. Was sich bei meinen Recherchen zum Glück nicht bewahrheitet hat.


tjo... dann mal ein frohes WE.

greetz

Dieser Beitrag wurde von nobido bearbeitet: 16. Februar 2013 - 10:54

0

#4 Mitglied ist offline   prunkster 

  • Gruppe: aktive Mitglieder
  • Beiträge: 264
  • Beigetreten: 22. Mai 08
  • Reputation: 3

geschrieben 17. Februar 2013 - 02:56

@nibido:

Soweit richtig zusammengefasst, besser als ich es hätte zusammenfassen können ;) (hätte sonst nur "scoping" erwähnen können)...
Einen kleinen Hinweis möchte ich noch geben, wenn du mit dem DataContractSerializer arbeitest (vom Beispiel ausgehend nehme ich an, dass du diesen einsetzt):

- Beim Deserialisieren des Objekts wird nicht der Constructor des Objekts "aufgerufen". Die Instanzierung des Objekts geschieht (wenn ich mich noch recht entsinne) mittels Activator.CreateInstance. Dadurch werden auch evtl. Standardwerte etc., die du im Constructor setzt, nicht initialisiert.

Was du in diesem Fall machen kannst, ist eine Methode zu implementieren, die mit dem "OnDeserialized"-Attribut annotiert ist. Diese wird dann direkt nach dem Deserialisieren aufgerufen.

Hat zwar nicht direkt mit dem Thema zu tun, aber vielleicht hilft es trotzdem irgendwann weiter (habe selbst ein bisschen gebraucht, bis ich das herausgefunden habe...)
Eingefügtes Bild <--- Workstation@Home

My Blog: hier
0

#5 Mitglied ist offline   nobido 

  • Gruppe: aktive Mitglieder
  • Beiträge: 157
  • Beigetreten: 20. April 07
  • Reputation: 6

geschrieben 17. Februar 2013 - 06:13

Hiho Prunkster,

scoping/scope, Neudeutsch auch Gültigkeitsbereich.

Hätte mir ohne Hinweis darauf, wie die Referenz übergeben wird, allerdings nicht weitergeholfen. War mir schlicht neu dass die Referenz an sich eben auch als byValue übergeben wird. Und sich deshalb die Referenz(variable) , was das Zuweisen eines neuen/anderen Objekt, ebenso verhält wie eine Variable, die byValue übergeben wird.

Was das (De)Serialisieren angeht... Ich hab da einfach im Kopf (und es mir auch so angelesen): Beim serialisieren wird das Objekt, samt seines Zustand, in was auch immer umgewandelt. Und dieses was auch immer kann dann in einer Datei gespeichert werden.
Umgekehrt: Die Objektdaten werden aus einer Datei gelesen und das Objekt anhand eines Bauplan (Klasse) wieder erzeugt. Dabei werden dann auch gleich wieder die (mitgespeicherten) Daten zugewiesen bzw. Objekteigenschaften gesetzt (Wäre ja blöd wenn ich was mit Werten speicher und dann wird da beim Wiederherstellen ein Konstruktur durchlaufen der mir ggf. die gespeicherten Werte kaputt macht). Wie das Objekt konkret erzeugt wird - sorry, da muss ich passen.

Die Activator.CreateInstance-Thematik... liest sich sehr interessant. Erinnert mich aber doch stark an Reflections - ein Thema was ich bereits vor langer Zeit hinter mir gelassen habe - ich sehe einfach keinen (für mich praktischen) Sinn darin und verstehe es auch nicht wirklich.
Und was den DataContractSerializer angeht: Sorry, noch nie von dem gehört *smile*. Aber vllt. guck ich mir das irgendwann mal an - obwohl ich es eigentlich aufgeben wollte mir noch mehr (unnützes) Wissen anzueignen. Aber, das ist dann schon ein anderes Thema.

Viele Worte - kurzer Sinn: Mir war einfach nicht klar dass die Referenz byValue übergeben wird und mit einer lokalen Kopie in der aufgerufenen Methode weitergearbeitet wird. Weshalb das Zuweises eines (anderen) Objekt nur innerhalb dieser (lokalen) Methode Auswirkungen hat.


Puh, nu isses aber schon recht spät. Oder früh. Je nachdem wie man guckt. Deshalb...

nettes Rest-WE noch.

greetz

Dieser Beitrag wurde von nobido bearbeitet: 17. Februar 2013 - 18:28

0

Thema verteilen:


Seite 1 von 1

1 Besucher lesen dieses Thema
Mitglieder: 0, Gäste: 1, unsichtbare Mitglieder: 0