Ich schreibe Code für die XML-Serialisierung. Mit unten stehender Funktion.
public static string SerializeToXml(object obj)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, obj);
return writer.ToString();
}
}
Wenn das Argument eine Klasseninstanz ohne parameterlosen Konstruktor ist, wird eine Ausnahme ausgelöst.
Nicht behandelte Ausnahme: System.InvalidOperationException: CSharpConsole.Foo kann nicht serialisiert werden, da es keinen parameterlosen Konstruktor gibt. unter System.Xml.Serialization.TypeDesc.CheckSupported () unter System.Xml.Serialization.TypeScope.GetTypeDesc (Typtyp, MemberInfo-Quelle, Boolean directReference, Boolean throwOnError) unter System.Xml.Serialization.ModelScope.GetType Boolesche direkte Referenz) unter System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping (Typ type, XmlRootAttribute root, String defaultNamespace) unter System.Xml.Serialization.XmlSerializer..ctor (Typ type, String defaultName space) unter System.Xml.Serialization. XmlSerializer..ctor (Typ Typ)
Warum muss es einen parameterlosen Konstruktor geben, damit die XML-Serialisierung erfolgreich ist?
EDIT: Danke für die Antwort von cfeduke. Der parameterlose Konstruktor kann privat oder intern sein.
quelle
XmlSerializer
erfordert einen standardmäßigen parameterlosen Konstruktor für die Deserialisierung.Antworten:
Während der De-Serialisierung eines Objekts erstellt die Klasse, die für die De-Serialisierung eines Objekts verantwortlich ist, eine Instanz der serialisierten Klasse und füllt die serialisierten Felder und Eigenschaften erst aus, nachdem eine Instanz zum Auffüllen erfasst wurde.
Sie können Ihren Konstruktor erstellen
private
oderinternal
wenn Sie möchten, nur solange er parameterlos ist.quelle
private
oder erstellen.internal
public
Dies ist eine Einschränkung von
XmlSerializer
. Beachten Sie, dassBinaryFormatter
undDataContractSerializer
nicht diese benötigen - sie eine nicht initialisierte Objekt aus dem Äther erstellen und initialisieren es während der Deserialisierung.Da Sie XML verwenden, können Sie
DataContractSerializer
Ihre Klasse verwenden und mit[DataContract]
/[DataMember
] markieren. Beachten Sie jedoch, dass dies das Schema ändert (z. B. gibt es kein Äquivalent zu[XmlAttribute]
- alles wird zu Elementen).Update: Wenn Sie es wirklich wissen möchten, verwenden Sie
BinaryFormatter
uaFormatterServices.GetUninitializedObject()
, um das Objekt zu erstellen, ohne den Konstruktor aufzurufen. Wahrscheinlich gefährlich; Ich empfehle nicht, es zu oft zu verwenden ;-p Siehe auch die Anmerkungen zu MSDN:Ich habe meine eigene Serialisierungs-Engine, habe aber nicht die Absicht, sie zu verwenden
FormatterServices
. Ich mag es zu wissen, dass ein Konstruktor ( jeder Konstruktor) tatsächlich ausgeführt hat.quelle
FormatterServices
Verwendung für EwigkeitenIXmlSerializable
aber a: das passiert nach dem Konstruktor und b: es ist sehr hässlich und schwer, es richtig zu machen (insbesondere Deserialisierung) - ich empfehle dringend, nicht zu versuchen, dies zu implementieren, aber: es erlaubt Ihnen nicht, Konstruktoren zu verwendenDie Antwort lautet: ohne guten Grund.
Im Gegensatz zu ihrem Namen wird die
XmlSerializer
Klasse nicht nur zur Serialisierung, sondern auch zur Deserialisierung verwendet. Es führt bestimmte Überprüfungen für Ihre Klasse durch, um sicherzustellen, dass es funktioniert, und einige dieser Überprüfungen sind nur für die Deserialisierung relevant, aber es führt sie trotzdem alle durch, da es nicht weiß, was Sie später tun möchten.Die Prüfung, die Ihre Klasse nicht besteht, ist eine der Prüfungen, die nur für die Deserialisierung relevant sind. Folgendes passiert:
Während der Deserialisierung muss die
XmlSerializer
Klasse Instanzen Ihres Typs erstellen.Um eine Instanz eines Typs zu erstellen, muss ein Konstruktor dieses Typs aufgerufen werden.
Wenn Sie keinen Konstruktor deklariert haben, hat der Compiler bereits einen standardmäßigen parameterlosen Konstruktor angegeben. Wenn Sie jedoch einen Konstruktor deklariert haben, ist dies der einzige verfügbare Konstruktor.
Wenn der von Ihnen deklarierte Konstruktor Parameter akzeptiert, können Sie Ihre Klasse nur instanziieren, indem Sie den Konstruktor aufrufen, der Parameter akzeptiert.
Es kann jedoch
XmlSerializer
keinen Konstruktor außer einem parameterlosen Konstruktor aufrufen, da nicht bekannt ist, welche Parameter an Konstruktoren übergeben werden sollen, die Parameter akzeptieren. Es wird also überprüft, ob Ihre Klasse einen parameterlosen Konstruktor hat, und da dies nicht der Fall ist, schlägt dies fehl.Wenn die
XmlSerializer
Klasse so geschrieben worden wäre, dass nur die für die Serialisierung relevanten Prüfungen durchgeführt würden, würde Ihre Klasse bestehen, da die Serialisierung absolut nichts erfordert, was einen parameterlosen Konstruktor erforderlich macht.Wie andere bereits betont haben, besteht die schnelle Lösung für Ihr Problem darin, einfach einen parameterlosen Konstruktor hinzuzufügen. Leider ist es auch eine schmutzige Lösung, da Sie keine
readonly
Mitglieder aus Konstruktorparametern initialisieren können.Darüber hinaus könnte die
XmlSerializer
Klasse so geschrieben worden sein, dass eine gleichmäßige Deserialisierung von Klassen ohne parameterlose Konstruktoren möglich ist. Alles was es brauchen würde, wäre "The Factory Method Design Pattern" (Wikipedia) zu verwenden. . Wie es aussah, entschied Microsoft, dass dieses Entwurfsmuster für DotNet-Programmierer viel zu weit fortgeschritten ist, die anscheinend nicht unnötig mit solchen Dingen verwechselt werden sollten. Daher sollten sich DotNet-Programmierer laut Microsoft besser an parameterlose Konstruktoren halten.quelle
For no good reason whatsoever,
dann sagen Sie weiter:XmlSerializer is not capable of invoking any constructor except a parameterless constructor, because it does not know what parameters to pass to constructors that accept parameters.
Wenn es nicht weiß, welche Parameter an einen Konstruktor übergeben werden sollen, wie würde es dann wissen, welche Parameter an eine Fabrik übergeben werden sollen? Oder welche Fabrik? Ich kann mir nicht vorstellen, dass dieses Tool einfacher zu verwenden ist. Sie möchten eine deserialisierte Klasse, lassen den Deserializer dann eine Standardinstanz erstellen und füllen dann jedes von Ihnen markierte Feld aus. Einfach.Zuallererst das, was in der Dokumentation geschrieben steht . Ich denke, es ist eines Ihrer Klassenfelder, nicht das Hauptfeld - und wie soll der Deserialisierer es ohne parameterlose Konstruktion wieder aufbauen?
Ich denke, es gibt eine Problemumgehung, um den Konstruktor privat zu machen.
quelle