Hallo,
ich habe ein merkwürdiges Phänomen beim Deserialisieren eines Objekts:
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream((byte[])viewRow["Settings"]);
object obj = formatter.Deserialize(stream);
_Settings = (ViewSettings)obj;
Die letzte Zeile wirft die Exception (Das Objekt des Typs ViewSettings kann nicht in Typ ViewSettings umgewandelt werden.
Betrachte ich mir im Debugger aber die Variable obj , dann enthält sie genau diesen Typ (ViewSettings).
Noch verschärfter:
Gebe ich die Anweisung
_Settings = (ViewSettings)obj;
im Überwachungsfenster ein, wirft dieses keinen Fehler und die Variable _Settings ist richtig belegt.
Was übersehe ich hier?
Was macht der ausgeführte Code anders als das Überwachungsfenster?
Thanx vorab
Ron
Riecht danach, dass du zwei Typen des Namens ViewSettings in zwei verschiedenen Namespaces hast.
Ich tippe auf Versionsghetto 🙂
Mit Version 1 serialisiert und mit Version 2 deserialisiert.
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
hi svenson,
stimmt, riecht voll danach, aber leider ist dem nicht so.
ich habe sogar schon per explorer-suche nach dem begriff ViewSettings im gesamten Entwicklungspfad gesucht; da ist definitiv nix doppelt deklariert.
hi hans
auch Dir danke, aber leider: nope.
datenzeile gelöscht, anwendung gestartet, in tabelle serialisiert, datensatz da, alles cool, dann deserialisiert, gleiches resultat.
hi alle anderen, 😉
gibt´s noch mehr ideen...?
Lass dir dochmal den FullQualifiedName des Typs des Objektes geben.
hi svenson,
objektvariable obj liefert beim debuggen als assembly und vollqualifizierten namen exakt das gleiche wie im überwachungsfenster die typdeklaration ViewSettings.
Alles stimmt haargenau überein, inkl. Assemblyversion.
Schliess mal die Entwicklungsumgebung und kille das Obj-Verzeichnis... ev. hilft es
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
Hallo citizen.ron,
ich gehe davon aus, dass die DLL, die ViewSettings definiert, zwischen Serialisieren und Deserialisieren neu übersetzt wurde. Ich denke, das reicht, damit ViewSettings nicht mehr als der gleiche Typ angesehen wird.
herbivore
danke herbivore,
aber das ist definitiv nicht so.
ich habe es nach deinem post explizit nochmals probiert:
datenzeile löschen, anwendung starten, anwendung beendet => serialisierung in tabellenzeile und -feld, anwendung erneut gestartet, deserialisierung schlägt fehl.
das objekt ist zwar ein bisschen komplexer, weil es dictionaries enthält, aber dennoch - die exception ist schlicht unerklärlich; im überwachungsfenster kann ich wie gesagt die zuweisung problemlos vornehmen - als codeanweisung kracht sie aber. außerdem hat es irgendwann mal funktioniert.
zur vertiefung hier noch das zu serialisiernde objekt (Ziel des ganzen ist, in der datenbank zu speichern, welche spaltenausblendungen, sortierungen, selektionen & markierungen etc. ein benutzer in einer beliebigen tabellenansicht vorgenommen hat):
using System;
using System.Collections.Generic;
using System.Text;
using CCL.Common;
using System.Windows.Forms;
namespace CAF.Views
{
partial class View
{
// InformationCategorySetting
/// <summary>
/// Category dependant settings
/// </summary>
[Serializable()]
public class InformationCategorySetting : IInformationCategorySetting
{
#region Property-bound members
private Guid _Selection;
private Type _SubviewType;
private eRecordsetView _RecordsetView;
private List<Guid> _HighlightedItems;
private List<String> _HiddenColumns;
public SortedList<int, string> _GroupingColumns;
[NonSerialized]
private ContextMenuStrip _ContextMenuStrip;
#endregion
#region Properties
public Guid Selection
{
get { return _Selection; }
set { _Selection = value; }
}
public Type SubviewType
{
get { return _SubviewType; }
set { _SubviewType = value; }
}
public eRecordsetView RecordsetView
{
get { return _RecordsetView; }
set { _RecordsetView = value; }
}
public List<Guid> HighlightedItems
{
get { return _HighlightedItems; }
set { _HighlightedItems = value; }
}
public List<String> HiddenColumns
{
get { return _HiddenColumns; }
set { _HiddenColumns = value; }
}
public SortedList<int, string> GroupingColumns
{
get { return _GroupingColumns; }
set { _GroupingColumns = value; }
}
public ContextMenuStrip ContextMenuStrip
{
get { return _ContextMenuStrip; }
set {_ContextMenuStrip = value; }
}
#endregion
#region .ctor
// Plain constructor for deserialization
public InformationCategorySetting()
{
_GroupingColumns = new SortedList<int,string>();
_HiddenColumns = new List<String>();
_HighlightedItems = new List<Guid>();
_RecordsetView = eRecordsetView.DataGrid;
}
// Initialization constructor for use in application
public InformationCategorySetting(Type type) : this()
{
_SubviewType = type;
_Selection = Guid.Empty;
}
#endregion
}
// ViewSettings
/// <summary>
/// A class designed for XML Serialization storing user settings of a view
/// </summary>
[Serializable()]
public class ViewSettings
{
#region Public members
public string SelectedCategory;
public Dictionary<string, IInformationCategorySetting> CategorySettings;
#endregion
#region .ctor
// Plain constructor for deserialization
public ViewSettings()
{
SelectedCategory = string.Empty;
CategorySettings = new Dictionary<string, IInformationCategorySetting>();
}
#endregion
}
#region Associated properties
private Dictionary<string, eRecordsetView> _AvailableRecordsetContainers;
public Dictionary<string, eRecordsetView> AvailableRecordsetContainers
{
get { return _AvailableRecordsetContainers; }
set {_AvailableRecordsetContainers = value; }
}
#endregion
}
}
Probier mal die Daten zu serialisieren und ohne die Anwendung zu beenden wieder zu deserialisieren.... falls dies funktioniert, dann liegt es definitiv an der Version des Assembly.
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
Hallo zusammen,
falls jemand mal in die gleiche Falle läuft, hier also heute die Lösung.
Man deklariere eine Schnittstelle IFoo für Foo und dann gehts 😉
protected internal void LoadSettings(DataRow viewRow)
{
// Read binary settings
if (viewRow["Settings"] != DBNull.Value) try
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream((byte[])viewRow["Settings"]);
object obj = formatter.Deserialize(stream);
if (obj is IViewSettings)
_Settings = (IViewSettings)obj;
}
catch {}
if (_Settings == null)
_Settings = new ViewSettings();
}
PS:
Ich weiß zwar immer noch nicht, woher der Fehler kommt, denn ohne Schnittstelle tritt er immer noch auf, aber so wird zur Laufzeit das Objekt wenigstens als IViewSettings erkannt.
hth
ron
Naja das ist ja nu keine Lösung, sondern nur ein Workaround. Aber wenn es mit Schnittstelle geht liegt es definitiv nicht an der Assemblyversion und die Deserialisierung an sich ist auch i.O....
Hallo citizen.ron
hast du es auch mal mit der Variante von Programmierhans versucht?
lg
LastGentleman
"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein
@LastGentleman
ja, klappt ebenfalls nicht.
direkt nach der serialisierung zu deserialisieren liefert im programmcode exakt den gleichen fehler, im überwachungsfenster aber keinen
ps:
ja, ich habe die aktuellsten servicepacks an allen fronten installiert 😉