I am serializing an structure by using BinaryFormatter using this code:
private void SerializeObject(string filename, SerializableStructure objectToSerialize)
{
Stream stream = File.Open(filename, FileMode.Create);
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Serialize(stream, objectToSerialize);
stream.Close();
}
Which objectToSerialize is my structure, I'm calling this function like this:
SerializableStructure s = new SerializableStructure();
s.NN = NN;
s.SubNNs = SubNNs;
s.inputs = inputs;
SerializeObject(Application.StartupPath + "\\Save\\" + txtSave.Text + ".bin", s);
Which SerializableStructure, and Type of NN, SubNNs and inputs are serializable. (inputs contains some Points, Rectangles and generic lists).
Now, When I run my code, I am given this error:
Type 'MainProject.Main' in Assembly 'MainProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
Why I'm given this error? Main is my form, and these variables are located in my form.
I have successfully serialized Type of NN with MemoryStream and VB.NET , But I don't know why I'm getting this error?
Here is the definition of my structures:
SerializableStructure:
[Serializable()]
public class SerializableStructure
{
public List<Inputs> inputs = new List<Inputs>();
public NeuralNetwork NN;
public NeuralNetwork[] SubNNs;
}
Inputs:
[Serializable()]
public class Inputs
{
public string XPath { get; set; }
public string YPath { get; set; }
public string ImagePath { get; set; }
public string CharName { get; set; }
public string CharBaseName { get; set; }
public List<double> x { get; set; }
public List<double> y { get; set; }
public List<double> DotsX { get; set; }
public List<double> DotsY { get; set; }
public List<Point> GravityCenters { get; set; }
public List<Rectangle> Bounds { get; set; }
public override string ToString()
{
return CharName;
}
public Inputs(string xPath, string yPath, string imagePath, string charName, string charBaseName)
{
XPath = xPath;
YPath = yPath;
ImagePath = imagePath;
CharName = charName;
CharBaseName = charBaseName;
x = new List<double>();
y = new List<double>();
GravityCenters = new List<Point>();
Bounds = new List<Rectangle>();
}
}
Also NN is very big structure(!).
This almost alwas means you have an event (or other delegate - maybe a callback) somewhere in your object model, that is trying to be serialized. Add [NonSerialized] to any event-backing fields. If you are using a field-like event (the most likely kind), this is:
[field:NonSerialized]
public event SomeDelegateType SomeEventName;
Alternatively: most other serializers don't look at events/delegates, and provide better version-compatibility. Switching to XmlSerializer, JavaScriptSerializer, DataContractSerializer or protobuf-net (just 4 examples) would also solve this by the simple approach of not trying to do this (you almost never intend for events to be considered as part of a DTO).
The problem is that you are trying to serialize a class derived from Form. The Form class is fundamentally unserializable. It has an enormous amount of internal state that is highly runtime dependent. That starts with an obvious property like Handle, a value that's always different. Less obvious are properties like Size, dependent on user preferences like the size of the font for the window caption. Ends with all the text, location and sizes for the controls, they are subject to localization. The odds that a serialized Form object can be properly deserialized anywhere at any time to create an exact clone of the form are zero.
Microsoft made no bones about it when they wrote the code, they simply omitted the [Serializable] attribute from the class declaration. Which is why you get the exception.
You'll have to aim lower, write your own class to capture your form's state. And give it the attribute. You'll need to write a bunch of code that maps between the form and control properties to an object of that class, back and forth.
Related
I have a class like this
public class basic
{
public bool Success { get; set; } = false;
public string Message { get; set; } = string.Empty;
}
public class ServiceResponse<T>:basic
{
public T? Data { get; set; }
}
public class ServiceResponse2<T> : basic
{
public T?[] Data { get; set; }
}
And I invoke it in my controller like this
ServiceResponse2<string> response = new ServiceResponse2<string>();
response.Success = true;
response.Message = "success";
response.Data[0] = filename;
response.Data[1] = outname;
when I do, I get runtime error in my lastline as: Object reference not set to an instance of an object. I hovered on top of Data variables and the values were null. Can I know what I'm missing here? Apologies if its a dumb doubt
The problem is that Data is an array, and this is never initialized to an object. You need to initialize it, for example:
response.Data = new string[]{filename, outname};
Or
public T?[] Data { get; set; } = new T[2];
However, I would be careful with using an array like this. What does Data means? How should it be used? Why can I change it however and whenever I want? How is it related to the other properties? Does a specific index have some special meaning? Does it promise to hold some specific number of items?
If this is intended to be used for requests to some type of service it is normal to use some form of serialization to convert objects to data. And this is normally done fairly close to the communication layer, so that most of the code can handle typed objects, and only a small part need to handle bits and bytes.
Here is an example class provided by Marc Gravel in his introduction on how to use Protobuf.net:
[ProtoContract]
class Person {
[ProtoMember(1)]
public int Id {get;set;}
[ProtoMember(2)]
public string Name {get;set;}
[ProtoMember(3)]
public Address Address {get;set;}
}
[ProtoContract]
class Address {
[ProtoMember(1)]
public string Line1 {get;set;}
[ProtoMember(2)]
public string Line2 {get;set;}
}
I have some questions, which I could not find the answers for after searching the web:
If on day 1, I know that I don't need the name property [ProtoMember(2)], then if I omit the [ProtoMember(2)] attribute, will Protobut.net ignore that property and not include it in the output serialized data? If true, then when the data is deserialized on the other end - what is Name initialized to - null?
Lets say that all 3 properties are initially serialized as shown above. If in the future, it turns out that the name property [ProtoMember(2)] is no longer required, can the [ProtoMember(2)] attribute be safely omitted so that only the first and third property are serialized? If true, would it be OK to simply leave the attribute numbers as shown (i.e. 1 & 3)? Any caveats if this is the case?
If it is OK to omit a serialization attribute for a property in a class, then what happens if the class definition on the deserialization side is out of sync? For example, say that the deserialization class defines all 3 properties above, but the serialization code only defines 1 and 3? Likewise, if the deserialization code only expects to see properties 1 and 3, but the serialization code sends all 3, would that still work or will it generate an error?
correct; in terms of what it is initialized to - that's usually up to your type, so in this case (since your type doesn't initialize it), yes: null (note: there is also an option in which the constructor can be suppressed, in which case it would be null even if your class had a constructor / initializer)
yes, that's fine (and expected)
the addition and removal of properties is expected and normal, so the library forgives either; when unexpected fields are received, what happens next depends on whether your class implements IExtensible (often by subclassing Extensible) - if it does, the unexpected data is stored separately, so that it can still be queried manually, or (more common) "round tripped" (i.e. if you serialize it again, the extra data is persisted, even though you didn't expect it)
(yes I know you didn't ask a 4) - the library also supports "conditional serialization", where-by properties can be omitted based on conditions - for example public bool ShouldSerializeName() => Name != null && SomethingElse == 42;
Since others may want to know the answer to these questions, I decided to post the question and share my findings.
These questions are actually quite easy to solve with a test program:
class Program
{
static void Main(string[] args)
{
var person = new Person1
{
Id = 12345,
Name = "Fred",
Address = new Address
{
Line1 = "Flat 1",
Line2 = "The Meadows"
}
};
//
byte[] arr = Serialize(person);
Person2 newPerson = Deserialize(arr);
/*
using (var file = File.Create("person.bin"))
{
Serializer.Serialize(file, person);
}
//
Person newPerson;
using (var file = File.OpenRead("person.bin"))
{
newPerson = Serializer.Deserialize<Person>(file);
}
*/
}
public static byte[] Serialize(Person1 person)
{
byte[] result;
using (var stream = new MemoryStream())
{
Serializer.Serialize(stream, person);
result = stream.ToArray();
}
return result;
}
public static Person2 Deserialize(byte[] tData)
{
using (var ms = new MemoryStream(tData))
{
return Serializer.Deserialize<Person2>(ms);
}
}
}
[ProtoContract]
class Person1
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
[ProtoMember(3)]
public Address Address { get; set; }
}
[ProtoContract]
class Address
{
[ProtoMember(1)]
public string Line1 { get; set; }
[ProtoMember(2)]
public string Line2 { get; set; }
}
[ProtoContract]
class Person2
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
[ProtoMember(3)]
public Address Address { get; set; }
}
So, to try out if Protobuf.net will ignore the Name property when serializing, first run the code in debug to see the total number of bytes with all 3 properties serialized. This can be done by setting a breakpoint at the Serialize(person) line and examining the size of arr.
Then, remove the [ProtoMember(2)] attribute from the Name property of the Person1 class. Running the code in debug shows that it leaves it out because the number of bytes is 6 less than before. When the object is then deserialized back to an object of Person2, it then shows that the Name property is initialized to null.
After replacing the [ProtoMember(2)] attribute for the Name property in the Person1 class, remove this same attribute for the Person2 class. After debugging through the code, it shows that after the Deserialize call, the Person2.Name property is set to null.
So, it looks like Protobuf.net was well designed to be quite flexible, efficient, and in some ways is backwards compatible in that it supports removing of obsolete properties.
I am new to C# and WPF, and I am trying to define a new variable from a class and to give this new variable a value from an old variable and then make some changes to the new one. But the problem is that the new variable is still connected to the old variable and if I change anything in the new one, the changes will effect the old one:
MW.CurrentPreviewJob = addjob;
MW is another page than the page I am writing the code in,
and I define them as follows:
public static Job addjob;
public Job CurrentPreviewJob
{
get { return _currentPreviewJob; }
set {
_currentPreviewJob = value;
this.NotifyPropertyChanged("CurrentPreviewJob");
}
}
the class for the two variables is same and it is:
public partial class Job
{
public int JOB_ID { get; set; }
public string JOB_DESCRIPTION { get; set; }
public byte[] TARGET_IMAGE { get; set; }
public int JOB_USER { get; set; }
}
So how can I take the value of CurrentPreviewJob without stay connecting to it?
This is because an object of a class is a reference type.
Let's take a look at an example:
We create an object of your class:
Job someJob = new Job();
What exactly is someJob? Well, when you create an instance of an object it is held in special area of memory, and someJob holds a reference to it (which is an address under which the program can find the instance in the memory).
So when you do something like:
Job someOtherJob = someJob;
you actually tell someOtherJob object to hold reference to the same address in a memmory as someJob object. that's how reference types work.
Now, if you do, for example:
someOtherJob.JOB_DESCRIPTION = "I changed that description in some other job object";
This is what happens: program checks the address which is referenced by somOtherJob object, goes there, finds the instance, and change its JOB_DESCRIPTION property's value. BUT remember that someJob objct (the "old" one) has a reference to the same instance in the memory - hnce, it will have the same, changed JOB_DESCRIPTION.
The most elegant thing to do here is to implement some kind of cloning method on the Job class.
public partial class Job
{
public int JOB_ID { get; set; }
public string JOB_DESCRIPTION { get; set; }
public byte[] TARGET_IMAGE { get; set; }
public int JOB_USER { get; set; }
public Job Clone() {
Job clone = new Job();
clone.JOB_ID = this.JOB_ID;
clone.JOB_DESCRIPTION = this.JOB_DESCRIPTION;
clone.TARGET_IMAGE = this.TARGET_IMAGE;
clone.JOB_USER = this.JOB_USER;
return clone;
}
}
and use it like:
Job someOtherJob = someJob.Clone();
That happens because both CurrentPreviewJob and addjob are reference types. They both reference the same object in the memory. So whatever you do to one variable will also affect the other, since they are pointing to the same object. You can make your Job have a Clone method like this:
public partial class Job
{
public int JOB_ID { get; set; }
public string JOB_DESCRIPTION { get; set; }
public byte[] TARGET_IMAGE { get; set; }
public int JOB_USER { get; set; }
public Job Clone()
{
return new Job {
JOB_ID = this.JOB_ID,
JOB_DESCRIPTION = this.JOB_DESCRIPTION,
TARGET_IMAGE = this.TARGET_IMAGE,
JOB_USER = this.JOB_USER
};
}
}
Then you can assign your CurrentPreviewJob like this:
MW.CurrentPreviewJob = addjob.Clone();
This will make another object so your second variable is no longer linked to your previous.
Or another way is to make your class a struct
The problem is because Job is a class, and classes are reference types, meaning that if you assign one job variable to another, you just have too variables referencing the same data.
You could declare Job as a struct, which are value types and assignment would automatically create a copy.
I tend to avoid structs, simply because I don't like having to copy things around just to change properties, so I'd suggest adding an appropriate constructor to Job, like:
public Job(Job other) {
this.JOB_ID = other.JOB_ID;
this.JOB_DESCRIPTION = other.JOB_DESCRIPTION;
//...same for the other fields
}
Once you have the constructor, you can clone the object by doing:
var NewJob = new Job(OldJob);
Some sample code below. The interesting/problem case is the Data property in
Mad. This code blows up (null value in the enumerable). Also, it works if i don't use the static attributes but instead the runtime type model, where i put in member.SupportNull = true for the fields (which is the behaviour i want), so what am i missing in the attributes / settings? Google search seems to indicate this is an open issue with probuf-net? That the same functionality is not available via attributes?
As as aside, if someone could suggest a way - i really love the runtime type model, i want to use that everywhere with a nice compiled model... but with it i lose the object versioning that protocol buffers solves! (via explicit tags). Is there any good way to maintain object version compatibility (simply adding fields) without doing all the static notation with fixed tags?
Basically the key thing with the runtime model is the assignment of tag indices and i can't think of a way of handling versions without explicitly specifying the tag indices via attributes...
[ProtoContract]
[ProtoInclude(1, typeof(ing))]
public class Eff
{
[ProtoMember(2)]
public string gg { get; set; }
}
[ProtoContract]
public class ing : Eff
{
[ProtoMember(1)]
public int zz { get; set; }
}
[ProtoContract]
public class Mad
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public IEnumerable<ing> Data { get; set; }
[ProtoMember(3)]
public ing Single { get; set; }
}
private static void Main(string[] args)
{
var obj = new Mad
{
Name = "test"
,Data = new[] { new ing {gg = "ooga", zz = -101},null,new ing()}
,Single = new ing {gg = "abc", zz = -999}
};
var m = new MemoryStream();
Serializer.Serialize(m, obj);
m.Seek(0, SeekOrigin.Begin);
var copy = Serializer.Deserialize<Mad>(m);
}
Short answer, it seems unavailable via attributes.
Workaround i'm doing for now - for every single type of interest(including the whole inheritance hierarchy) - add it to the type model yourself (with default handling so that it processes attributes), then call .GetFields() and set .SupportNull = true for each field (or only the relevant one)
I am trying to define C# objects based on this XML:
<UPDs LUPD="86">
<UPD ID="106">
<ER R="CREn">
<NU UID="1928456" />
<NU UID="1886294" />
<M>
<uN>bob ยท </uN>
<mO>fine :D</mO>
</M>
So far I have:
public class UDPCollection
{
List<UDP> UDPs;
public UDPCollection()
{
UDPs = new List<UDP>();
}
}
public class UDP
{
public int Id;
public List<ER> ERs;
public UDP(int id, List<ER> ers)
{
Id = id;
ERs = ers;
}
}
public class ER
{
public string LanguageR;
public ER(string languager)
{
LanguageR = languager;
}
}
My questions: What do elements map to in C#? Classes? What do attributes map to? Properties? Am I going about this the correct way?
Use the XmlSerializer class and the XmlRoot, XmlElement and XmlAttribute attributes. For example:
using System.Xml.Serialization;
...
[XmlRoot("UPDs")]
public class UDPCollection
{
// XmlSerializer cannot serialize List. Changed to array.
[XmlElement("UPD")]
public UDP[] UDPs { get; set; }
[XmlAttribute("LUPD")]
public int LUPD { get; set; }
public UDPCollection()
{
// Do nothing
}
}
[XmlRoot("UPD")]
public class UDP
{
[XmlAttribute("ID")]
public int Id { get; set; }
[XmlElement("ER")]
public ER[] ERs { get; set; }
// Need a parameterless or default constructor.
// for serialization. Other constructors are
// unaffected.
public UDP()
{
}
// Rest of class
}
[XmlRoot("ER")]
public class ER
{
[XmlAttribute("R")]
public string LanguageR { get; set; }
// Need a parameterless or default constructor.
// for serialization. Other constructors are
// unaffected.
public ER()
{
}
// Rest of class
}
The code to write out the XML is:
using System.Xml.Serialization;
...
// Output the XML to this stream
Stream stream;
// Create a test object
UDPCollection udpCollection = new UDPCollection();
udpCollection.LUPD = 86;
udpCollection.UDPs = new []
{
new UDP() { Id= 106, ERs = new [] { new ER() { LanguageR = "CREn" }}}
};
// Serialize the object
XmlSerializer xmlSerializer = new XmlSerializer(typeof(UDPCollection));
xmlSerializer.Serialize(stream, udpCollection);
Not that the XmlSerializer adds additional namepsaces but it can parse XML without them if needed. The output of the above is:
<?xml version="1.0"?>
<UPDs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" LUPD="86">
<UPD ID="106">
<ER R="CREn" />
</UPD>
</UPDs>
Use the Deserialize() method to parse it from XML into an object.
XML elements and attributes don't necessarily map to anything in particular in C#. You can make them map to classes and properties if you want, but it's not required.
That said, if you want to map your existing XML to some sort of C# data structures, the way you're doing it seems reasonable - I'd just recommend replacing your public fields with actual properties, and maybe making the list properties a less specific type - say, IEnumerable, or ICollection, or IList if they really need to be in order.