I have a class that I want to construct, by deserializing it from a network stream.
public Anfrage(byte[] dis)
{
XmlSerializer deser = new XmlSerializer(typeof(Anfrage));
Stream str = new MemoryStream();
str.Write(dis, 0, dis.Length);
this = (Anfrage)deser.Deserialize(str);
}
The intention is that I just want to pass the byte[] and have a proper object, rather than using a method in another class.
Now, I know that I obviously cannot do this =.
I've read this question and currently am reading the article mentioned in it, but I am not sure wether I'm understanding it correctly.
Is my intention clear enough?
Is there a way to do what I want to get done here?
Thank you all.
You cannot overwrite an object within the class itself by assigning to this.
You can for example create a method that returns a new instance:
public static Anfrage Create(byte[] dis)
{
XmlSerializer deser = new XmlSerializer(typeof(Anfrage));
Stream str = new MemoryStream();
str.Write(dis, 0, dis.Length);
return (Anfrage)deser.Deserialize(str);
}
Then you can instantiate one like this:
var anfrage = Anfrage.Create(bytes);
Usually with this problem is dealt with a static non-constructor function returning the Object.
public static Anfrage Create(byte[] dis)
{
XmlSerializer deser = new XmlSerializer(typeof(Anfrage));
Stream str = new MemoryStream();
str.Write(dis, 0, dis.Length);
return (Anfrage)deser.Deserialize(str);
}
if you want to have a new object and edit it, make the constructor private instead of public and acces it with you static construction function
Related
Can anyone tell me how to use Salar Bois serialization to disk?
I want to do the right thing since I'm optimizing both by size and time.
Specifically I had to serialize a List lp;
All what I find on the site is:
How to serialize an object:
var boisSerializer = new BoisSerializer();
using (var mem = new MemoryStream())
{
boisSerializer.Serialize(this, mem);
return mem.ToArray();
}
How to deserialize an object:
var boisSerializer = new BoisSerializer();
return boisSerializer.Deserialize<SampleObject>(dataStream);
Thanks
Patrick
Basically, you want to use a FileStream instead of a MemoryStream.
There's an example at the bottom of this MSDN page:
https://msdn.microsoft.com/en-us/library/system.io.filestream(v=vs.110).aspx
To use your code example however:
var boisSerializer = new BoisSerializer();
using (var fileStream = File.Create("c:\myfile.obj"))
{
boisSerializer.Serialize(this, fileStream);
}
Clearly, your return object will change, so you'll have to account for how you're using this code.
I have an object, instance of a Serializable class. I was wondering how can you get this object as a byte stream?
I know I can use BinaryFormatter and then use the Serialize method, but this method takes a serializationStream where it writes the serialized object. I want to be able to write it in a file/stream in a specific position so I would like to do something like:
obj = new Something(); // obj is serializable
byte[] serialized = obj.serialize(); [*]
file.write(position, serialized)
Is there any way I can do the [*], to take the bytes of the serialization of an object?
MemoryStream m = new MemoryStream();
var formatter = new BinaryFormatter();
formatter.Serialize(m, new MyClass() {Name="SO"});
byte[] buf = m.ToArray(); //or File.WriteAllBytes(filename, m.ToArray())
[Serializable]
public class MyClass
{
public string Name;
}
Hi I just started working with C# WPF and I read about Serialization to store or load your data. My Question is how can I store a class that contains a list of another class and some additional parameters?
My first class (MeterValues) contains a number of parameters (type,speed,etc..)
public class MeterValues{}
I now made a second class to store a list containing multiple instances of the first class type. (So if I have 3 different meters, this list size = 3)
public class MeterValuesList : IList<MeterValues>{}
Now I wish to add an additional parameter to the second class, something independent of the first class so it should only be saved once. (not for every instance of class1)
To make my problem clear, I could add the extra parameter to the first class, but then If I have 100 different meters, the parameter is stored 100 times, and I only need to store it once.
Any idea on how to do this?
PS: If you need any additional information please just ask, I'm very eager to learn and to assist you in helping me solve this problem. Thanks in advance.
UPDATE:
I'm able to save the class MeterValuesList to a .xml file but only the List gets stored in the file, the extra parameter does not show up (It is in the class right before I write it to the file, checked it with debugger but does not show up in the file)
MeterValuesList meterValuesList = DataContext as MeterValuesList;
meterValuesList.CommSettings = "Com5:19200,8,n,1";
FileStream stream = null;
try
{
stream = new FileStream(filename, FileMode.Create, FileAccess.Write);
XmlSerializer serializer = new XmlSerializer(typeof(MeterValuesList));
serializer.Serialize(stream, meterValuesList);
stream.Close();
}
This is the result after saving the class to an xml file. The extra parameter is missing.
<?xml version="1.0"?>
<ArrayOfMeterValues xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MeterValues></MeterValues>
</ArrayOfMeterValues>
Unless you plan on overriding or expanding the functionality that an IList has in place, there is no reason to inherit from it in your MeterValuesList class. This feels like a case of using a "has a" relationship instead of an "is a" relationship.
Try this instead:
public class MeterValuesGroup
{
List<MeterValues> MeterList { get; set; }
int ExtraParameter { get; set; }
// whatever additional parameters you need here.
}
If you do need to inherit from IList or IEnumerable, you can do something similar. However, in order to serialize this class correctly, you'll have to implement IXmlSerializable in MeterValues and MeterValuesList.
(Here is an excellent example of how this will look: Proper way to implement IXmlSerializable?)
public class MeterValuesList : IList<MeterValues>, IXmlSerializable
{
MeterValues[] _MeterList { get; set; }
string CommSettings = "Com5:19200,8,n,1";
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteAttributeString("CommSettings ", CommSettings );
foreach (var mv in _MeterList)
{
// kind of a bad example, but hopefully you get the idea
if (mv== null)
return;
writer.WriteStartElement("MeterValues");
mv.WriteXml(writer);
writer.WriteEndElement();
}
}
You can add this property in the second class MeterValueList and serilize this class and when you deserialize it , that additional property will be assigned.
MeterValueList m = new MeterValueList();
m.AdditionalParameter = 100;
MemoryStream memorystream = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(memorystream, m);
byte[] yourBytesToDb = memorystream.ToArray();
//here you write yourBytesToDb to database
//----------read from database---------------------
//here you read from database binary data into yourBytesFromDb
MemoryStream memorystreamd = new MemoryStream(yourBytesFromDb);
BinaryFormatter bfd = new BinaryFormatter();
MeterValueList md = bfd.Deserialize(memorystreamd) as MeterValueList ;
var i = md.AdditinalParameter; // must print 100
When I am deserializing my object back to it's original type my object is always null.
Here is my code:
ProjectSetup obj = new ProjectSetup();
if (System.Web.HttpContext.Current.Session["ProjectSetup"] == null)
setBookProjectSetup();
string toDeserialise = System.Web.HttpContext.Current.
Session["ProjectSetup"].ToString();
DataContractSerializer dcs = new DataContractSerializer(typeof(ProjectSetup));
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(toDeserialise));
obj = (ProjectSetup) dcs.ReadObject(ms, true);
return obj;
I'm going to assume that the call to setBookProjectSetup places an instance of ProjectSetup in the HttpSessionState with a key of ProjectSetup.
The issue here starts with this:
string toDeserialise = System.Web.HttpContext.Current.
Session["ProjectSetup"].ToString();
You subsequently use the contents of the toDeserialize string as the source of the deserialization.
Unless you've overloaded ToString to return a byte stream that the DataContractSerializer would be able to deserialize (it's highly unlikely) chances are you are using the implementation of ToString on Object, which will just return the type's name.
Then, you are trying to deserialize that string into your object, which isn't going to work.
What you need to do is properly serialize your object into a byte array/MemoryStream, like so:
using (var ms = new MemoryStream())
{
// Create the serializer.
var dcs = new DataContractSerializer(typeof(ProjectSetup));
// Serialize to the stream.
dcs.WriteObject(ms, System.Web.HttpContext.Current.Session["ProjectSetup"]);
At this point, the MemoryStream will be populated with a series of bytes representing your serialized object. You can then get the object back using the same MemoryStream:
// Reset the position of the stream so the read occurs in the right place.
ms.Position = 0;
// Read the object.
var obj = (ProjectSetup) dcs.ReadObject(ms);
}
I have a small issue accessing a byte[]:
I have a binary object (byte[] saved to mssql db) which I get from the db and I want to read it. Whenever I access it, for its length or for its Read() method, I get a Cannot access a closed Stream exception.
What's the best way to treat binaries if they have to be updated in the code and than saved again to the db?
Thanks.
Edit - code
In this application we convert a test object to a generic data object we've created to simplify, so this is the data object:
public class DataObject
{
public Stream Content { get; set; }
public Descriptor Descriptor { get; set; }
}
The descriptor contains metadata only (currently only name and description strings) and is not relevant, I think.
The test is more complicated, I'll start by adding the mapping into data object. The serializer mentioned is NetDataContractSerializer.
public DataObject Map(Test test)
{
using(var stream = new MemoryStream())
{
Serialize(test, stream);
return new DataObject { Content = stream, Descriptor = test.Descriptor };
}
}
private void Serialize(Test test, MemoryStream stream)
{
serializer.WriteObject(stream, test);
stream.Flush();
stream.Position = 0;
}
and vice versa:
public Test Build(DataObject data)
{
using (var stream = data.Content)
{
var test = Deserialize(stream);
test.Descriptor = data.Descriptor;
return test ;
}
}
private Test Deserialize(Stream stream)
{
return serializer.ReadObject(stream) as IPythonTest;
}
Edit II - trying to change the test's content:
This is my first attempt handling streams, I'm not sure I'm doing it right, so I'll explain first what I want to do: The information in data field should be saved into the test's data object.
private static void UpdateTestObject(DataObject data, Test test)
{
var testData = new byte[data.Content.Length];
data.Content.Read(testData, 0, (int) data.Content.Length);
test.TestObject = testData;
}
The exception is thrown in UpdateTestObject when accessing data.Content. I get it after creating some test, mapping it, and trying to save it.
data.Content.Read(testData, 0, (int) data.Content.Length);
Here we go. The data object has a Content stream that it closed.
Result: Error.
Reasno? TOTALLY (!) unrelated to your question. Basically find out why / what is the problem there in your data handling.
Could be a design fubar in which the stream is not available after a certain point and youru sage of the object is past this point.
So the problem is caused by the Map() method - as far as I could understand, since it used:
using (var stream = new MemoryStream())
{ ... }
The stream was disposed of at the end of the block. Changing it to declaring a MemoryStream and then using it afterwards worked.
Thanks to everyone who gave it a thought (not mentioning reading all this code)! :)