In my project I'm using a List<Name> for storing data.
Now I wanted to save the List via XMLSerialization:
XmlSerializer listser = new XmlSerializer(typeof(List<Name>)); //Stops here, jumps back to screen/GUI
FileStream liststr = new FileStream(xmlSaveFile_Dialog.FileName, FileMode.Create);
listser.Serialize(liststr, nameslist.list);
liststr.Close();
Now the method simply stops at the XmlSerializer declaration.(There's no exception!)
I'm using exactly the same method before to serialize another object (List<File>).
This works without problems.
Now my code:
Name-Class:
[Serializable()]
public class Name
{
//[XmlElement("name")]
public string name { get; set; }
//[XmlElement("index")]
public string index { get; set; }
public Name(string name, string index)
{
this.name = name;
this.index = index;
}
}
Name-List:
[XmlRoot("Units")]
class Namelist
{
[XmlArray("Unitlist")]
[XmlArrayItem("Unit", typeof(Name))]
public List<Name> list;
// Constructor
public Namelist()
{
list = new List<Name>();
}
public void AddNameData(Name item)
{
list.Add(item);
}
}
In the main I declare this in the constructor:
nameslist = new NameList(); //this a global internal variable
Exactly the same way I did it with the List<File> object...
Name is not XML serializable in its present definition. The XML serializer cannot handle classes that lack a public parameterless ctor. So you should basically include the following ctor to Name:
public Name()
{
}
Hope this helps.
Related
I have the following class serialized into a file using BinaryFormatter:
[Serializable]
public class TestClass
{
public String ItemTwo { get; set; }
public String ItemOne { get; set; }
}
Using this code:
FileStream fs = new FileStream("DataFile.dat", FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, new TestClass{ItemOne = "ItemOne", ItemTwo = "ItemTwo"});
fs.Close();
When deserializing using this code:
FileStream fs = new FileStream("DataFile.dat", FileMode.Open);
BinaryFormatter formatter = new BinaryFormatter();
TestClass addresses = (TestClass)formatter.Deserialize(fs);
fs.Close();
I get everything normally.
However, now I need the class to have some backing fields like so:
[Serializable]
public class TestClass
{
private string _itemTwo;
private string _itemOne;
public String ItemTwo
{
get { return _itemTwo; }
set { _itemTwo = value; }
}
public String ItemOne
{
get { return _itemOne; }
set { _itemOne = value; }
}
}
My problem is that now, for some reason, deserialization from previous version doesn't work anymore. I get the class but the Properties are left null.
I cannot affect the serialization process, or the former class state.
How can I get the file to deserialize to the current class?
If you try to serialize the first version of TestClass the backfields will be serialized automatically by the binary formatter. Auto properties are only syntactic sugar, the compiler transform them in normal properties with backing fields. If you decompile your original console application (or class library) with ILSpy for example you'll see that your private fields are declared as:
.field private string '<ItemOne>k__BackingField'
which is way different from your second declaration with backing fields which yields to:
.field private string _itemOne
An approach would be declaring the ISerializable interface on your TestClass and get the value of the original properties using the information contained in the class SerializationInfo
[Serializable]
public class TestClass : ISerializable
{
private string _itemTwo;
private string _itemOne;
public String ItemTwo
{
get { return _itemTwo; }
set { _itemTwo = value; }
}
public String ItemOne
{
get { return _itemOne; }
set { _itemOne = value; }
}
protected TestClass(SerializationInfo info, StreamingContext context)
{
_itemTwo = info.GetString("<ItemTwo>k__BackingField");
_itemOne = info.GetString("<ItemOne>k__BackingField");
}
[SecurityPermissionAttribute(SecurityAction.Demand,
SerializationFormatter = true)]
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
//Add data to your serialization process here
}
}
so you tell the BinaryFormatter how you want your backing fields to be initialized during deserialization.
I have 2 classes StaggingAttorney and Attorney. I will use the StaggingAttorney to collect information about an attorney and once I have all the information I will use it to create an Attorney profile using the best results. The 2 classes look like this;
private class StaggingAttorney : CourtCase.Attorney
{
public bool scraping = false;
public bool scraped = false;
public string caseNumber;
public CourtCase.Attorney toAttorney()
{
CourtCase.Attorney attorney = new CourtCase.Attorney();
return attorney;
}
}
...and...
public class Attorney
{
public string names;
public string matchString;
...
public List<Identity> IdentityMatches = new List<Identity>();
public List<Identity> getIdentityMatches()
{
return IdentityMatches;
}
public class Identity
{
public string names;
public string barNumber;
public string email;
public string phoneNumber { get; internal set; }
public object faxNumber { get; internal set; }
}
}
I have created a method called CourtCase.Attorney toAttorney() which you can see above. In this method I want to return a new CourtCase.Attorney with all CourtCase.Attorney inherited properties in the the StaggingAttorney
As #derloopkat suggested, you can simply cast your "StaggingAttorney" instance to his parent class. ("Attorney" in this case)
But if you really need a new instance of an "Attorney" with the same values than the parent "StaggingAttorney" just access to the parent fields of your "StaggingAttorney" object.
private class StaggingAttorney : CourtCase.Attorney
{
public bool scraping = false;
public bool scraped = false;
public string caseNumber;
public CourtCase.Attorney toAttorney()
{
CourtCase.Attorney attorney = new CourtCase.Attorney()
{
names = this.names,
matchString = this.matchString,
[... Initialize the other properties ...]
};
return attorney;
}
}
When you create an instance of a child class you are also creating the parent. So there are no many scenarios where you need to make another new instance from a child.ToParent() method. Having a conversion method like this makes more sense when one class is not inheriting from the other.
var attorney = new StaggingAttorney() { scraped = false };
attorney.names = "John"; //During the scraping process
attorney.scraped = true;
CourtCase.Attorney court = (CourtCase.Attorney)attorney; //casting
Console.WriteLine(court.names); //returns "John"
No need to copy data, because the child inherited names from its parent.
Is it somehow possible that base class can access fields in inherited class (has-a relationship)?
class BasicClass
{
public InheritedClass objTemp = new InheritedClass();
public BasicClass()
{
//Now i want to get some information from objTemp fields.
//But Name is protected, what should I do here?
objTemp.Name.Length();
}
}
class InheritedClass
{
protected string Name;
}
Maybe there are some tricky things that I don't know how to manage, or maybe it is better to create some more clever class hierarchy. Anyway thank you in advance.
Sorry for missunderstanding.In few words i have class Game which consist another class WordsContainer.
class Game
{
private Player objGamer;
private WordsContainer objWordsClass = new WordsContainer();
public Game()
{
Console.Title = "Hangman";
Console.Write("Player name information:");
string localName = Console.ReadLine();
objGamer = new Player(localName);
StringBuilder bumpWord = new StringBuilder(objWordsClass.getKeyWord().Length);
}
class WordsContainer
{
/// <summary>
/// WordsContainer class contains a list of strings from wich with getKeyWord method
/// we could get string type key.
/// </summary>
private List<string> wordBank = new List<string>() {"stack","queue","heap","git","array"};
public WordsContainer(){}
public string getKeyWord()
{
Random random = new Random((int)DateTime.Now.Ticks);
return wordBank[random.Next(0, wordBank.Count)];
}
So is it possible in this way somehow hide public string getKeyWord().
If you want to keep going on the code you have now, you could just define a public string GetName() function in InheritedClass and call it from the object that you create in the BasicClass
class BasicClass
{
public InheritedClass objTemp = new InheritedClass();
public BasicClass()
{
int nameLength = objTemp.GetName().Length();
}
}
class InheritedClass
{
protected string Name;
public string GetName()
{
return Name;
}
}
I have this code:
[DataContract]
class MyData
{
private Int32 dato1;
[DataMember]
public Int32 Dato1
{
get { return dato1; }
set { dato1 = value; }
}
public MyData(Int32 dato1)
{
this.dato1 = dato1;
}
public MyData()
{
this.dato1 = 0;
}
}
[DataContract]
class MyCollection2 : List<MyData>
{
public MyCollection2()
{
}
}
Then I try to serialize one object of MyCollection2 with:
MyCollection2 collec2 = new MyCollection2();
collec2.Add(new MyData(10));
DataContractSerializer ds = new DataContractSerializer(typeof(MyCollection2));
using (Stream s = File.Create(dialog.FileName))
{
ds.WriteObject(s, collec2);
}
Then I get the next exception:
InvalidDataContractException is an invalid collection type since it
have DataContractAttribute
However, if I use the next class (doesn't inherit directly from List, instead has a List member):
[DataContract]
class MyCollection1
{
[DataMember]
public List<MyData> items;
public MyCollection1()
{
items = new List<MyData>();
}
}
Here Serialization works ok. Do you know why ?.
Thanks very much.
Use [CollectionDataContract(...)] instead of [DataContract]. For more details see here.
For full details see here.
I have a List<object> with different types of objects in it like integers, strings, and custom types. All custom types are protobuf-adjusted.
What I wanna do now is to serialize / deserialize this list with protobuf.net. Up until now I suspect that I have to declare each and every type explicitly, which is unfortunately not possible with these mixed-list constructs. Because the binary formater has no problems to do these things I hope that I missed something and that you can help me out.
So my question is how to deal with objects in protobuf.net.
(disclosure: I'm the author of protobuf-net)
BinaryFormatter is a metadata-based serializer; i.e. it sends .NET type information about every object serialized. protobuf-net is a contract-based serializer (the binary equivalent of XmlSerializer / DataContractSerializer, which will also reject this).
There is no current mechanism for transporting arbitrary objects, since the other end will have no way of knowing what you are sending; however, if you have a known set of different object types you want to send, there may be options. There is also work in the pipeline to allow runtime-extensible schemas (rather than just attributes, which are fixed at build) - but this is far from complete.
This isn't ideal, but it works... it should be easier when I've completed the work to support runtime schemas:
using System;
using System.Collections.Generic;
using ProtoBuf;
[ProtoContract]
[ProtoInclude(10, typeof(DataItem<int>))]
[ProtoInclude(11, typeof(DataItem<string>))]
[ProtoInclude(12, typeof(DataItem<DateTime>))]
[ProtoInclude(13, typeof(DataItem<Foo>))]
abstract class DataItem {
public static DataItem<T> Create<T>(T value) {
return new DataItem<T>(value);
}
public object Value {
get { return ValueImpl; }
set { ValueImpl = value; }
}
protected abstract object ValueImpl {get;set;}
protected DataItem() { }
}
[ProtoContract]
sealed class DataItem<T> : DataItem {
public DataItem() { }
public DataItem(T value) { Value = value; }
[ProtoMember(1)]
public new T Value { get; set; }
protected override object ValueImpl {
get { return Value; }
set { Value = (T)value; }
}
}
[ProtoContract]
public class Foo {
[ProtoMember(1)]
public string Bar { get; set; }
public override string ToString() {
return "Foo with Bar=" + Bar;
}
}
static class Program {
static void Main() {
var items = new List<DataItem>();
items.Add(DataItem.Create(12345));
items.Add(DataItem.Create(DateTime.Today));
items.Add(DataItem.Create("abcde"));
items.Add(DataItem.Create(new Foo { Bar = "Marc" }));
items.Add(DataItem.Create(67890));
// serialize and deserialize
var clone = Serializer.DeepClone(items);
foreach (DataItem item in clone) {
Console.WriteLine(item.Value);
}
}
}
List<YourClass> list;
ProtoBuf.Serializer.Deserialize<List<YourClass>>(filestream);
There is a way of doing this, albeit not a very clean way, by using a wrapper object that utilises another serialisation mechanism that supports arbitrary objects. I am presenting an example below using JSON but, like I said, resorting to a different serialisation tool seems like defeating the purpose of using protobuf:
[DataContract]
public class ObjectWrapper
{
[DataMember(Order = 1)]
private readonly string _serialisedContent;
[DataMember(Order = 2)]
private readonly string _serialisedType;
public object Content { get; private set; }
[UsedImplicitly]
private ObjectWrapper() { }
public ObjectWrapper(object content)
{
_serialisedContent = JsonConvert.SerializeObject(content);
_serialisedType = content.GetType().FullName;
Content = content;
}
[ProtoAfterDeserialization]
private void Initialise()
{
var type = Type.GetType(_serialisedType);
Content = type != null
? JsonConvert.DeserializeObject(_serialisedContent, type)
: JsonConvert.DeserializeObject(_serialisedContent);
}
}
EDIT: This can also be done using C#'s built-in binary serialisation
[DataContract]
public class ObjectWrapper
{
[DataMember(Order = 1)]
private readonly string _serialisedContent;
public object Content { get; private set; }
[UsedImplicitly]
private ObjectWrapper() { }
public ObjectWrapper(object content)
{
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, content);
stream.Flush();
stream.Position = 0;
_serialisedContent = Convert.ToBase64String(stream.ToArray());
}
}
[ProtoAfterDeserialization]
private void Initialise()
{
var data = Convert.FromBase64String(source);
using (var stream = new MemoryStream(data))
{
var formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
return formatter.Deserialize(stream);
}
}
}