I have a bunch of simple data objects of different types (all properties are writable, no hidden state). Is there any automated way to clone such objects?
(yes, I know the way to clone them manually. Just don't want to ^_^)
Serialize them in a (memory)stream and deserialize them back.
Serializing and deserializing would clone your object. Of course, the object would need to be serializable.
public static T Clone<T>(T source)
{
IFormatter formatter = new BinaryFormatter();
using (Stream stream = new MemoryStream())
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
The best approach is to implement IClonable interface in all objects but in case that objects developed not by you its not appropriate way for you.
The second way ( most universal in my opinion) is to use reflection:
public T CommonClone<T>(T Source)
{
T ret = System.Activator.CreateInstance<T>();
Type typeDescr = typeof(T);
if (typeDescr.IsClass != true)
{
ret = Source;
return ret;
}
System.Reflection.FieldInfo[] fi = typeDescr.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
for (int i = 0; i < fi.Length; i++)
{
fi[i].SetValue(ret, fi[i].GetValue(Source));
}
return ret;
}
The code above will copy both public and private fields. If you need to cope only public ones, just remove BindingFlags.NonPublic from GetFields method call.
This way not specified any limitation on objects which can use. Its working both for classes and structures.
using System.Web.Helpers;
public static T Clone<T>(T source)
{
return Json.Decode<T>(Json.Encode(source));
}
You might see this
Deep cloning objects
Take a look at second answer. I use it all the time and it works great. The only drawback of this solution is the fact that class must be serializable
Related
I'm trying to find the best way to make copies of a pretty big class. It has somewhere around 80 properties. I could of course code them all in a normal copy constructor, but I'm not sure how nice that would look in code.
So I'm thinking... Is there a way to iterate through the properties of obj A and assign the the values to the corresponding properties of obj B?
This queston is marked as a duplicate, but it is not. My question is not how to make a deep copy, the question is how to iterate through the properties and thus make a normal copy constructor with many properties.
Here is one way:
public static T DeepClone<T>(T original)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "original");
}
if (ReferenceEquals(original, null))
{
return default(T);
}
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter
{
Context = new StreamingContext(StreamingContextStates.Clone)
};
formatter.Serialize(stream, original);
stream.Position = 0;
return (T) formatter.Deserialize(stream);
}
}
This is adapted from CLR via C# by Jeffrey Richter.
You use it like this:
var objB = DeepClone(objA);
The type must be serializable for this to work, though.
I have a problem cloning dynamic object with the code like this:
public void Execute(IPrepareData entity)
{
try
{
dynamic data = entity.Primary as dynamic;
data.PreviousInfo = deepClone(data.Info);
}
catch (Exception ex)
{
data.Errors.Add(ex.Message);
}
}
private static T deepClone<T>(T obj)
{
if (typeof(T).IsClass || typeof(T).IsArray)
{
if (ReferenceEquals(obj, null))
{
return default(T);
}
}
using (var memoryStream = new MemoryStream())
{
BinaryFormatter fieldFormatter = new BinaryFormatter();
fieldFormatter.Serialize(memoryStream, obj);
memoryStream.Position = 0;
return (T)fieldFormatter.Deserialize(memoryStream);
}
}
dynamic data;
I don't know the structure of entity in advance (only that it will contain Info, and I don't know the structure of info) and that it won't be marked serializable. I need to copy this info to previous info section of entity.
Result of execution of this code is 'Object reference not set to an instance of an object' on fieldFormatter.Serialize line.
How can I check if it is an instance of an object?
There might be (most probably will be) circular references, so I am not trying reflection as I am not sure how to deal with that. Also speed is not an issue.
What about
var clone = JsonConvert.DeserializeObject<dynamic>(JsonConvert.SerializeObject(obj));
If you don't know that the data will be marked serializable, then you can't rely on using BinaryFormatter.
If the object is likely to have circular references, a lot of other serializers are out of the question.
If we assume it is the general case of dynamic (and not just ExpandoObject), then there is no way of getting information about the members, since they can be invented as they are queried.
Basically, this scenario *has no good answer. There is no magic way to just deep clone "a thing".
I have been using JSON.net for serializing user defined types and it has been working well.
There are flags to ignore null properties, or it will by default save as
{propname: 'undefined'}
I know you mentioned speed as not being an issue, but the serializer is very fast.
Here is the nuget package.
I'm trying to implement a custom formatter using the .NET IFormatter interface.
After a couple of hours of search, I just found a very basic sample which unfortunately doesn't include recursion. I also tried with Reflector to look at BinaryFormatter and SoapFormatter, but they are rather complex.
My question is:
Should I implement recursion myself, or there's something I've missed in FormatterServices?
Following my code:
public void Serialize(Stream serializationStream, object graph)
{
// Get fields that are to be serialized.
MemberInfo[] members = FormatterServices.GetSerializableMembers(graph.GetType(), Context);
// Get fields data.
object[] data = FormatterServices.GetObjectData(graph, members);
// Write class name and all fields & values to file
StreamWriter sw = new StreamWriter(serializationStream);
string accumulator = string.Empty;
for (int i = 0; i < data.Length; ++i)
{
// Skip this field if it is marked NonSerialized.
if (Attribute.IsDefined(members[i], typeof(NonSerializedAttribute)))
continue;
FieldInfo field = (FieldInfo)members[i];
if (field.FieldType.IsPrimitive)
{
}
else //TODO: What should I do here?
}
sw.Close();
}
If by recursion you mean traversing through the object tree then yes, it up to you when you implement your own IFormatter.
Simply check if the value of the property is not null and if it is implementing IFormatter interface. If it is then just call it and use the value it returns.
If not then it is up to you again: you may throw an exception saying that IFormatter must be implemented, or just fall-back to some sort of default formatter (XML or Binary one).
The recursion per se is tricky. When, let's say, the object references itself, you need to be smart enough to handle this situation and not to end up with the infinite loop:
public class A {
public object SomeProperty { get; set; }
}
var a = new A();
a.SomeProperty = a;
There are a number of tricky aspects in implementing formatters, like what if two properties are actually reference the same object? Will you serialize/format it twice or just once and keep the information about these references somehow?
You don't probably need this if you want just one-way serialization, but if you want to be able to restore the object it might be important...
I'm building an XNA game and I'm trying to save game/map etc. state completely, and then be able to load and resume from exactly the same state.
My game logic consists of fairly complex elements (for serializing) such as references, delegates etc. I've done hours of research and decided that it's the best to use a DataContractSerializer that preserves the object references. (I also got around for delegates but that's another topic) I have no problem serializing and deserializing the state, re-creating the objects, the fields, lists, and even object references correctly and completely. But I've got a problem with cyclic references. Consider this scenario:
class X{
public X another;
}
//from code:
X first = new X();
X second = new X();
first.another = second;
second.another = first;
Trying to serialize X will result in an exception complaining about cyclic references. If I comment out the last line it works fine. Well, I can imagine WHY it is happening, but I have no idea HOW to solve it. I've read somewhere that I can use the DataContract attribute with IsReference set to true, but it didn't change anything for me -- still got the error. (I want to avoid it anyway since the code I'm working on is portable code and may someday run on Xbox too, and portable library for Xbox doesn't support the assembly that DataContract is in.)
Here is the code to serialize:
class DataContractContentWriterBase<T> where T : GameObject
{
internal void Write(Stream output, T objectToWrite, Type[] extraTypes = null)
{
if (extraTypes == null) { extraTypes = new Type[0]; }
DataContractSerializer serializer = new DataContractSerializer(typeof(T), extraTypes, int.MaxValue, false, true, null);
serializer.WriteObject(output, objectToWrite);
}
}
and I'm calling this code from this class:
[ContentTypeWriter]
public class PlatformObjectTemplateWriter : ContentTypeWriter<TWrite>
(... lots of code ...)
DataContractContentWriterBase<TWrite> writer = new DataContractContentWriterBase<TWrite>();
protected override void Write(ContentWriter output, TWrite value)
{
writer.Write(output.BaseStream, value, GetExtraTypes());
}
and for deserialization:
class DataContractContentReaderBase<T> where T: GameObject
{
internal T Read(Stream input, Type[] extraTypes = null)
{
if (extraTypes == null) { extraTypes = new Type[0]; }
DataContractSerializer serializer = new DataContractSerializer(typeof(T), extraTypes, int.MaxValue, false, true, null);
T obj = serializer.ReadObject(input) as T;
//return obj.Clone() as T; //clone falan.. bi bak iste.
return obj;
}
}
and it's being called by:
public class PlatformObjectTemplateReader : ContentTypeReader<TRead>
(lots of code...)
DataContractContentReaderBase<TRead> reader = new DataContractContentReaderBase<TRead>();
protected override TRead Read(ContentReader input, TRead existingInstance)
{
return reader.Read(input.BaseStream, GetExtraTypes());
}
where:
PlatformObjectTemplate was my type to write.
Any suggestions?
SOLUTION: Just a few minutes ago, I've realized that I wasn't marking the fields with DataMember attribute, and before I added the DataContract attribute, the XNA serializer was somehow acting as the "default" serializer. Now, I've marked all the objects, and things are working perfectly now. I now have cyclic references with no problem in my model.
If you don't want to use [DataContract(IsReference=true)] then DataContractSerializer won't help you, because this attribute is the thing that does the trick with references.
So, you should either look for alternative serializers, or write some serialization code that transforms your graphs into some conventional representation (like a list of nodes + a list of links between them) and back, and then serialize that simple structure.
In case you decide to use DataContract(IsReference=true), here's a sample that serializes your graph:
[DataContract(IsReference = true)]
class X{
[DataMember]
public X another;
}
static void Main()
{
//from code:
var first = new X();
var second = new X();
first.another = second;
second.another = first;
byte[] data;
using (var stream = new MemoryStream())
{
var serializer = new DataContractSerializer(typeof(X));
serializer.WriteObject(stream, first);
data = stream.ToArray();
}
var str = Encoding.UTF8.GetString(data2);
}
The str will contain the following XML:
<X z:Id="i1" xmlns="http://schemas.datacontract.org/2004/07/GraphXmlSerialization"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<another z:Id="i2">
<another z:Ref="i1"/>
</another>
</X>
Referencing this answer to a question.
Can this be rewritten as:
private static BinaryFormatter formatter = new BinaryFormatter();
public static T DeepClone<T>(this T a)
{
using(MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, a);
stream.Position = 0;
return (T)formatter.Deserialize(stream);
}
}
So avoiding constructing (and GC'ing) a new BinaryFormatter for each call?
This code path is getting hit very frequently as it involves our caching layer and I would like to make it as lightweight as possible.
Thanks.
According to MSDN:
Any public static (Shared in Visual
Basic) members of this type are thread
safe. Any instance members are not
guaranteed to be thread safe.
So you need to synchronize access to Serialize/Deserialize methods.
Have you identified particular performance issues by creating a local serializer instance every time?
UPDATE:
I would trust MSDN because even if in some cases we can verify that instance members might be thread safe this doesn't mean that with the next service pack/update/framework version this will continue to be the case.
Looking with Reflector at BinaryFormatter constructor:
public BinaryFormatter()
{
this.m_typeFormat = FormatterTypeStyle.TypesAlways;
this.m_securityLevel = TypeFilterLevel.Full;
this.m_surrogates = null;
this.m_context = new StreamingContext(StreamingContextStates.All);
}
And StreamingContext constructor:
public StreamingContext(StreamingContextStates state, object additional)
{
this.m_state = state;
this.m_additionalContext = additional;
}
Quite frankly assigning 6 properties (most of which are enums) should be blindingly fast. IMHO most of the time would be spent in Serialize/Deserialize methods.
You could use the [ThreadStatic] attribute and initialize if value is null. This will work assuming your reusing threads.
[ThreadStatic]
private static BinaryFormatter formatter = null;
public static T DeepClone<T>(this T a)
{
if( formatter == null ) formatter = new BinaryFormatter();
using(MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, a);
stream.Position = 0;
return (T)formatter.Deserialize(stream);
}
}
Of course, the other option is to use Relfector.Net from Red Gate and review the implementation of the binary formatter. After reading the code you should be able to decide if it is safe for cross threaded use; however, Darin is correct in that it could break in a future release.