it4baer
Goto Top

Singletone Objekt in Datei speichern

Hallo,

ist es möglich ein Singleton-Objekt zu "serialisieren" und dann in eine Datei zu speichern ... um es später wieder laden zu können?

wenn ja, wie ist hier die Herangehensweise

Vielen Dank

Content-ID: 365337

Url: https://administrator.de/contentid/365337

Ausgedruckt am: 22.11.2024 um 10:11 Uhr

emeriks
emeriks 20.02.2018 um 08:10:16 Uhr
Goto Top
Hi,
wenn man ein Instanz einer Klasse serialisieren kann, dann kann man das Byte Array auch in eine Datei schreiben und von dort wieder laden und die Instanz der Klasse daraus wieder deserialisieren. Ob man eine Klasse serialisieren kann, hängt im Wesentlichen von den verwendeten Datentypen der Member ab.

Ist Deine Frage jetzt wie man generell serialisiert oder wie man speziell ein Singleton-Objekt serialisiert?

E.
it4baer
it4baer 20.02.2018 um 08:28:11 Uhr
Goto Top
Hm,

vielen Dank... gute Frage...
ich habe gesehen, man kann eine Singleton-Klasse erweitern und dann die Felder zum Serialisieren zurückgeben... aber das ist mal wieder Aufwand der es nicht gerechtfertigt...

Interessant wäre eigentlich das Objekt "ohne" Veränderung ... zumindest großer Veränderung zu Serialisieren... in meiner Singleton sind neben Parametern (Bool, Int und String) auch z.B. DataSets.

Ich stell mir immer vor, alles muss ja irgendwie (z.B. im Arbeitsspeicher) in Nullen und Einsen abgelegt werden... nun stellt sich die Fragen ob man nicht das Irgendwie abgreifen kann und eben wieder Nachladen.

speichern <- mal einfach ausgedrückt
Singleton mySingle = Singleton.Init
byte saveData = mySingle.serialize;
saveData => toFile

laden
fromFile => saveData
Singleton mySingle = saveData.deserialize;

die Singleton sollte dabei "wenn möglich" nicht oder nur minimal angepasst werden...
=> das ganze "komplett" umzuschreiben, wäre natürlich SICHER möglich... aber dann kann ich auch einfach die relevanten Felder abgreifen und Speichern/Laden (ich such also nach einen Effizienten und Eleganten Weg)

... nein, ich will nicht, dass man mir hier die Arbeit macht und obwohl ich nicht das Rad neu erfinden will, hab ich auch nichts gegen Fleißarbeit... aber es gibt bekannterweise viele Wege welche nach Rom führen und ich suche den "effizientesten" <- also nicht zwingend den Kürzesten aber auch nicht den, bei welchen der komplette Sprit drauf geht, nur um erster zu sein...
emeriks
Lösung emeriks 20.02.2018 aktualisiert um 08:41:25 Uhr
Goto Top
Nu vergiss mal das Singleton. Das hat ja m.E. nichts damit zu tun. Es ändert nichts, ob das Objekt nun ein Singleton ist oder nicht. Oder?

Mit u.g. Code kann man Objekte in Byte Arrays "umwandeln" und vice versa.
Aber auch nur dann, wenn alle verwendeten Datentypen innerhalb der Klasse dies unterstützen.
Die Klasse muss als serialisierbar gekennzeichnet sein.

Basic serialization
Object Serialization in the .NET Framework


 ''' <summary>  
  ''' Liefert ein beliebiges Objekt als eindimensionales Byte-Array zurück.  
  ''' </summary>  
  ''' <param name="TheObject">Das zu "übersetzende" Objekt.</param>  
  ''' <returns>Byte-Array</returns>  
  Public Function ObjectToByteArray(ByVal TheObject As Object) As Byte()
    Try
      Dim ms As New System.IO.MemoryStream()
      Dim bf As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
      bf.Serialize(ms, TheObject)
      Return ms.ToArray()
    Catch Ex As Exception
      Return Nothing
    End Try
  End Function

  ''' <summary>  
  ''' Liefert ein beliebiges, eindimensionales Byte-Array als Objekt zurück.  
  ''' </summary>  
  ''' <param name="ByteArray">Das zu "übersetzende" Byte-Array.</param>  
  ''' <returns>Object</returns>  
  Public Function ByteArrayToObject(ByVal ByteArray() As Byte) As Object
    Try
      Dim ms As New System.IO.MemoryStream(ByteArray)
      Dim bf As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
      ms.Position = 0
      Return bf.Deserialize(ms)
    Catch Ex As Exception
      Return Nothing
    End Try
  End Function
it4baer
it4baer 21.02.2018 aktualisiert um 10:58:53 Uhr
Goto Top
funktioniert perfekt...

ich habe noch eine andere Anwendung in welcher ein INotifyPropertyChanged inkludiert ist...
zwar speichert und Lädt er die Singleton perfekt, aber die Oberfläche ist irgendwie außenvor
=> was so viel heißt dass beim ersten jungfreulichen Laden alles gut funktioniert, er die Daten beim Beenden speichert, beim Laden die Daten lädt, aber die Oberfläche erstens die Werte nicht zugeordnet bekommen und 2. auch neue Werte aus der Oberfläche nicht in die Singleton übernimmt.

mein Singleton sieht so aus:

[Serializable]
public class Singleton : INotifyPropertyChanged
{
	private readonly List<Delegate> _serializableDelegates;

	private static Singleton instance;
	private Singleton()
	{
		_serializableDelegates = new List<Delegate>();
	}

	public static Singleton Instance
	{
		get
		{
			if (instance == null)
			{
				instance = new Singleton();
			}
			return instance;
		}
	}

	public DataTable MyTable { get; set; }
	public bool AdminMode = false;

	private string text;
	public string Text
	{
		get { return text; }
		set
		{
			if (text != value)
			{
				text = value;
				OnPropertyChanged(new PropertyChangedEventArgs("Text"));  
			}
		}
	}

	[field: NonSerialized]
	public event PropertyChangedEventHandler PropertyChanged;
	protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
	{
		PropertyChanged?.Invoke(this, e);
	}

	protected void OnPropertyChanged(string propertyName)
	{
		OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
	}

	[OnSerializing]
	private void OnSerializing(StreamingContext context)
	{
		_serializableDelegates.Clear();
		var handler = PropertyChanged;

		if (handler != null)
		{
			foreach (var invocation in handler.GetInvocationList())
			{
				if (invocation.Target.GetType().IsSerializable)
				{
					_serializableDelegates.Add(invocation);
				}
			}
		}
	}

	[OnDeserialized]
	private void OnDeserialized(StreamingContext context)
	{
		foreach (var invocation in _serializableDelegates)
		{
			PropertyChanged += (PropertyChangedEventHandler)invocation;
		}
	}
}

Geladen wird das so:

singleton = LoadObject("singleton.bin") == null ? Singleton.Instance : (Singleton)LoadObject("singleton.bin");

die Methode welche ich zum Laden benutz...
private object LoadObject(string fileName)
{
	if (File.Exists(fileName))
	{
		try
		{
			using (FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read))
			{
				byte bytes = new byte[file.Length];
				file.Read(bytes, 0, (int)file.Length);

				try
				{
					using (MemoryStream ms = new MemoryStream())
					{
						BinaryFormatter bf = new BinaryFormatter();
						ms.Write(bytes, 0, (int)file.Length);
						ms.Position = 0;

						return bf.Deserialize(ms);
					}
				}
				catch(Exception ex)
				{
					MessageBox.Show("MS: " + ex.Message);  
				}
			}
		}
		catch (Exception ex)
		{
			MessageBox.Show("Loader: " + ex.Message);  
		}
	}
	return null;
}


weiß jemand warum das Zusammenspiel mit der Oberfläche nicht mehr richtig arbeitet?
emeriks
emeriks 21.02.2018 aktualisiert um 11:05:23 Uhr
Goto Top
Ich kann Dir, offen gestanden, nicht ganz folgen. Bitte post mal auch Teil, wo Du mit "LoadObject" das Objekt wieder lädst.

Wenn ich doch richtig verstanden habe:
Du hast ein Objekt mit "angehängtem" Eventhandler. Dieses serialisierst Du und speicherst es in eine Datei.
Beim erneuten Start deserialisierst dieses Objekt wieder aus dieser Datei und der Eventhandler funktioniert jetzt nicht?
Falls ja:
Das ist logisch. Wenn Du ein Objekt deserialisierst, dann ist das hinterher nicht mehr das selbe Objekt sondern ein neues, welches bloß die Eigenschaften des alten bekommen hat. Auch der Eventhandler ist jetzt ein anderer. Du müsstest also nach dem Deserialisieren die Eventhandler erneut "anhängen".
emeriks
emeriks 21.02.2018 um 11:27:27 Uhr
Goto Top
funktioniert perfekt...
Oh, keine Ursache ....
it4baer
it4baer 21.02.2018 um 12:22:00 Uhr
Goto Top
ja, du hast das richtig verstanden!

das klingt alles "logisch"

Du müsstest also nach dem Deserialisieren die Eventhandler erneut "anhängen".
Wie mach ich das?

muss ich da für jedes Feld agieren, oder kann ich das irgendwie Automatisieren?
emeriks
emeriks 21.02.2018 um 13:14:27 Uhr
Goto Top
Ein Code-Auszug von Dir wäre hilfreich. Es muss ja nicht gleich das ganze Formular sein.
it4baer
it4baer 21.02.2018 um 13:37:54 Uhr
Goto Top
nun, vom prinzip ist der oben genannte Code mein Code...

ich habe in der Oberfläche folgende Felder:
<TextBox Text="{Binding Path=Text, Source={x:Static local:Singleton.Instance}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

und das Singleton ist ja oben...

        private void SaveObject(object obj, string fileName)
        {
            try
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    bf.Serialize(ms, obj);

                    using (FileStream file = new FileStream(fileName, FileMode.Create, FileAccess.Write))
                    {
                        ms.WriteTo(file);
                    }
                }
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

hier noch das speichern

gerne liefer ich noch mehr... aber ich wüsste nicht was noch fehlt!?
emeriks
emeriks 21.02.2018 um 13:46:19 Uhr
Goto Top
Schreibe ich Spanisch?

Der Code, wo Du das Objekt deserialisierst! Welches Objekt ist das? Wie verwendest Du es weiter? Ist Dein Code soooo geheim? Wirst Du damit reich? Patent anmelden?
it4baer
it4baer 21.02.2018 um 13:57:10 Uhr
Goto Top
Sorry...

ich habe nahezu ALLES an code veröffentlicht!

Post um: 21.02.2018 um 13:37 Uhr
Hier ist die Funktion wo ich das Objekt Serialisiere...
aufgerufen wird diese:
SaveObject(Singleton.Instance, "datei.bin");

das "Objekt" der begierde
Post um: 21.02.2018, aktualisiert um 10:58 Uhr
public class Singleton : INotifyPropertyChanged
erzeugt wird das durch
Singleton.Instance.Text = "geheimer Code womit ich unglaublich viel Geld verdiene";

geladen wird das (im selben Post)
LoadObject("datei.bin");

bzw. ich machs mir einfach indem ich mir den Text Singleton.Instance spare und schreibe:

Singleton myData = Singleton.Instance;

und dann verwende ich myData.Text oder beschreibe myData.Text...
Serialisiert wird myData...

...
oder was willst du?
PS. ich mag es nicht, wenn man "unfreundlich" wird. Wenn man keine Lust hat mir zu helfen ist das Okay... wenn ich mich "sau Dumm" anstelle, dann ist das keine Absicht!
emeriks
emeriks 21.02.2018 aktualisiert um 14:35:13 Uhr
Goto Top
Ich muss blind sein ...
weiß jemand warum das Zusammenspiel mit der Oberfläche nicht mehr richtig arbeitet?
Welcher Oberfläche?
Welches Zusammenspiel?
Wie mach ich das?
muss ich da für jedes Feld agieren, oder kann ich das irgendwie Automatisieren?
Wie soll ich das beantworten, wenn ich nicht weiß, was Du da wie verlinkt hast?

Aber egal, ich bin raus.
Die Lösung für Dein eigentliches Serialiserungsproblem hast Du von mir bekommen, auch wenn nicht so von Dir markiert.

Viel Erfolg!