.net memberwiseclone shallow copy not working - c#

I am using this.MemberwiseClone() to create shallowcopy but it is not working. Please look at the code below.
public class Customer
{
public int Id;
public string Name;
public Customer CreateShallowCopy()
{
return (Customer)this.MemberwiseClone();
}
}
class Program
{
static void Main(string[] args)
{
Customer objCustomer = new Customer() { Id = 1, Name = "James"};
Customer objCustomer2 = objCustomer;
Customer objCustomerShallowCopy = objCustomer.CreateShallowCopy();
objCustomer.Name = "Jim";
objCustomer.Id = 2;
}
}
When I run the program, It shows objCustomerShallowCopy.Name as "James" rather than "Jim".
Any Ideas??

When you shallow copy the Customer object the objCustomerShallowCopy.Name will be James and will stay like that until you change that object. Now in your case the string "James" will gave 3 references to it (objCustomer, objCustomer2 and objCustomerShallowCopy).
When you are changing objCustomer.Name to Jim you are actually creating a new string object for the objCustomer object and releasing 1 ref to the "James" string object.

We have also had problems getting that to work. We have solved it by serializing and then deserializing the object.
public static T DeepCopy<T>(T item)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, item);
stream.Seek(0, SeekOrigin.Begin);
T result = (T)formatter.Deserialize(stream);
stream.Close();
return result;
}
Using the above code there will be no reference between the two objects.

Related

A constructor that takes object from same type

So I want to create constructor for my class EmployeeNodeClass that takes In EmployeeNodeClass object and copies it using a deepclone funtion:
public static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
to the new object.
At first i thought that it is as simple as
public EmployeeNodeClass(EmployeeNodeClass EMPND)
{
this = DeepClone(EMPND);
}
but then I got the error that this is readonly.
so how can I do it?
It can be done using NewtonSoft JsonConvert.PopulateObject:
Example:
class Entity
{
public List<int> List { get; set; }
public Entity(List<int> list)
{
List = list;
}
public Entity(Entity original)
{
string originalJson = JsonConvert.SerializeObject(original);
JsonConvert.PopulateObject(originalJson, this);
}
}
And using it:
static void Main(string[] args)
{
var entity1 = new Entity(new List<int> { 1, 2, 3 });
var entity2 = new Entity(entity1);
entity1.List[0] = 5;
Console.WriteLine(entity2.List[0]);
}
Note: since this uses NewtonSoft Json, it will only clone public, writable properties. So internal state in private fields (that are not associated with such properties) will be lost.

Attempting binary serialization of a C# data class, can't modify until return call has finished executing. Why?

I'm trying to create a visual novel engine. I have a data class containing information such as the position in the script. Right now it's very simple, just
[Serializable]
public class DataContainer
{
private List<string> stackStringList = new List<string>();
public int ScriptPosition { get; set; }
public List<string> StackStringList
{
get { return stackStringList; }
set { this.stackStringList = value; }
}
}
I then have a class to perform the save and load functions,
class SaveAndLoad
{
public static void SerializeWithBinaryFormatter(DataContainer data, string fileName)
{
Stream streamOut = File.OpenWrite(fileName);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(streamOut, data);
streamOut.Close();
}
public static object DeserializeWithBinaryFormatter(string fileName)
{
Stream streamIn = File.OpenRead(fileName);
BinaryFormatter formatter = new BinaryFormatter();
DataContainer obj = (DataContainer)formatter.Deserialize(streamIn);
streamIn.Close();
return obj;
}
}
Everything saves/loads sort of fine, but when I try to use the ScriptPosition property of the recently deserialized data container, it just returns the int default, 0, and I have to do it after the call to return obj has finished executing.
Inserting Console.Write methods before and after shows that, if I had previously saved ScriptPosition as, say, 3, it will indeed be three after the return obj line executes, but not inbetween the return line and the DataContainer obj = (DataContainer)formatter.Deserialize(streamIn); line.
What I would like to do is instead
public static object DeserializeWithBinaryFormatter(string fileName)
{
Stream streamIn = File.OpenRead(fileName);
BinaryFormatter formatter = new BinaryFormatter();
DataContainer obj = (DataContainer)formatter.Deserialize(streamIn);
// Do stuff with obj.ScriptPosition here
streamIn.Close();
return obj;
}
I have got around this by just calling the relevant functions after I call DeserializeWithBinaryFormatter, however I can't see why obj.ScriptPosition would return 0, whereas returning the same obj reference into test and calling test.ScriptPosition would return what I had previously saved.

XmlNodeConverter only supports deserializing XmlDocuments error when using Json DeserializeObject

I've the following class;
public class MyClass
{
[XmlIgnore]
public string Name { get; set; }
[XmlElement("Name")]
public XmlCDataSection sName
{
get { return new XmlDocument().CreateCDataSection(Name); }
set { Name = value.Value; }
}
}
I've the following function to take a List<> and copy it's contents;
private static T CloneList<T>(T source)
{
var serialized = JsonConvert.SerializeObject(source);
return JsonConvert.DeserializeObject<T>(serialized);
}
But in my code when I try;
List<MyClass> oMyClassList = new List<MyClass>();
MyClass oMyClass = new MyClass();
oMyClass.Name = "Hello World's";
oMyClassList.Add(oMyClass);
List<MyClass> oMyClonedClassList = new List<MyClass>(CloneList(oMyClassList));
At the point of executing the following
List<MyClass> oMyClonedClassList = new List<MyClass>(CloneList(oMyClassList));
I get the error XmlNodeConverter only supports deserializing XmlDocuments. The problem occurs because I've added XmlCDataSection into the class.
How can I get around this problem ?
I managed to overcome this problem by changing my CloneList code to the following
public static T DeepClone<T>(T obj)
{
T objResult;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, obj);
ms.Position = 0;
objResult = (T)bf.Deserialize(ms);
}
return objResult;
}
As provided by [Ajith][1] here How do I clone a generic list in C#?
[1]: https://stackoverflow.com/users/853645/ajith "ajith".
Also, to each of the classes that need to be cloned, I had to add [Serializable] at the top of each class as I was getting the exception 'Not marked as serializable'

Serializing a HashSet in a Dictionary

I have a similar Problem to Serializing a HashSet
I have a Class with a Member of type Dictionary<String,HashSet<T>>
When i serialize the Object with BinaryFormatter, and then deserialize it, it comes up empty.
I don't know how, or where to call the workaround posted here.
Any Hints? thanks in advance.
edit:
i tried to convert the hashset to a list, as one of the comments in the other thread suggested.
the object looks like this:
public class THashSet : HashSet<T> , ISerializable
{
public THashSet(SerializationInfo info, StreamingContext context)
{
var list = (List<T>)info.GetValue("hashset", typeof(List<T>));
foreach (T t in list)
this.Add(t);
}
public override void GetObjectData(SerializationInfo info,StreamingContext context)
{
info.AddValue("hashset", this.ToList<T>());
}
when the object containing the THashSet is deserialized (and the constructor is called), the list is recovered correctly, as i see in the debugger.
but after the serializer is done, the object only contains an empty hashset.
Suppose for your T object you haven't override methods GetHashCode and Equals. You need to do it.
UPD: All depends from your object implementation. And object is not so easy as you say. Your sitation, object:
[Serializable]
public class DataClass
{
public DataClass()
{
}
public DataClass(string name, string description)
{
Name = name;
Description = description;
this.Dictionary = new Dictionary<string, HashSet<DataClass>>();
}
public string Name { get; set; }
public string Description { get; set; }
public Dictionary<string, HashSet<DataClass>> Dictionary { get; set; }
}
And serialization/deserialization code:
DataClass dataClass = new DataClass("name", "descr");
dataClass.Dictionary.Add("key1", new HashSet<DataClass>() { new DataClass("sample11", "descr11"), new DataClass("sample12", "descr12") });
dataClass.Dictionary.Add("key2", new HashSet<DataClass>() { new DataClass("sample21", "descr21"), new DataClass("sample22", "descr22") });
dataClass.Dictionary.Add("key3", new HashSet<DataClass>() { new DataClass("sample31", "descr31"), new DataClass("sample32", "descr32") });
byte[] serialized;
var formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, dataClass);
serialized = stream.ToArray();
}
using (MemoryStream streamDeserial = new MemoryStream())
{
streamDeserial.Write(serialized, 0, serialized.Length);
streamDeserial.Seek(0, SeekOrigin.Begin);
var dictDeserial = formatter.Deserialize(streamDeserial) as DataClass;
}
This code works well.

Convert C# Object to and from Varbinary using Linq to SQL

I want to be able to save any C# object in a single column of a SQL database table. I am not clear how to convert the object into a varbinary or get it back from a varbinary. My SystemContextObjects table has an OptionValue column that is Varbinary(max).
var dc1 = new DataContextDataContext();
var optionUpdate = dc1.SystemContextObjects.SingleOrDefault(o => o.OptionId == OptionId && o.OptionKey == OptionKey);
if (optionUpdate != null)
{
optionUpdate.OptionValue = Value; <===== NEED HELP HERE...
optionUpdate.DateCreated = DateTime.Now;
optionUpdate.PageName = PageName;
var ChangeSet = dc1.GetChangeSet();
if (ChangeSet.Updates.Count > 0)
{
dc1.SubmitChanges();
return;
}
}
You can use a binary serializer for this, e.g. using the BinaryFormatter - but your classes must be serializable and be marked as such, here a simple example:
You have a simple Person class and mark it as serializable:
[Serializable]
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
}
You can then serialize it using a memory stream to extract a byte array representing the object:
Person p = new Person() { Name = "Fred Fish", Address = "2 Some Place" };
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, p);
ms.Position = 0;
byte[] personData = ms.ToArray(); // here's your data!
}
To re-create a Person object from a byte array you use de-serialization which works similar:
byte[] personData = ...
using (MemoryStream ms = new MemoryStream(personData))
{
BinaryFormatter formatter = new BinaryFormatter();
Person p = (Person)formatter.Deserialize(ms);
}
I wound up using JSON to accomplish this. I serialize/deserialize the class to/from a string and store that. Works fine.

Categories

Resources