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...
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 am trying to serialse a fingerprint FMD to XML using the code below, but get an error:
Error: DPUruNet.DataResult`1[DPUruNet.Fmd] cannot be serialized
because it does not have a parameterless constructor.
public void storePrint(DataResult<Fmd> resultConversion)
{
//store fingerprint as byte and insert to server------------
using (StreamWriter myWriter = new StreamWriter("test.txt", false))
{
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(resultConversion.GetType());
x.Serialize(myWriter, resultConversion);
}
MessageBox.Show("Fingerprint Stored!");
//------------------------------------------------------------
}
private void OnCaptured(CaptureResult captureResult)
{
try
{
// Check capture quality and throw an error if bad.
if (!_sender.CheckCaptureResult(captureResult)) return;
count++;
DataResult<Fmd> resultConversion = FeatureExtraction.CreateFmdFromFid(captureResult.Data, Constants.Formats.Fmd.ANSI);
SendMessage(Action.SendMessage, "A finger was captured. \r\nCount: " + (count));
if (resultConversion.ResultCode != Constants.ResultCode.DP_SUCCESS)
{
_sender.Reset = true;
throw new Exception(resultConversion.ResultCode.ToString());
}
preenrollmentFmds.Add(resultConversion.Data);
//--------------------CALL METHOD
storePrint(resultConversion);
//
The class DataResult is being referenced, so I can not alter it
UPDATE
If you don't have access to the DataResult<T> class, then you might have to take a slightly different approach and wrap this class with a different, serializable one. You can find a full example here:
How can I XML Serialize a Sealed Class with No Parameterless Constructor?
Previous Answer
The error is clear; you just need to add a parameterless constructor to the DataResult<T> class:
public class DataResult<T>
{
// Add a default constructor (public visibility, no parameters)
public DataResult()
{
// You can still define a method body if you wish,
// no restrictions there. Just don't do anything that
// could jeopardize the (de)serialization.
}
}
As for the implications of adding a default constructor, without knowing what
FeatureExtraction.CreateFmdFromFid(...)
is doing to create the DataResult<Fmd>, it would be impossible to know whether it would cause any issues.
Thanks to Cory, that is a useful answer, however in this example there is another way of serializing using
tempFingerPrint = Fmd.SerializeXml(resultConversion.Data);
this is specific to the Digital Persona SDK
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 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
When dealing with custom exceptions, I usually inherit from Exception and then add some fields/properties to my exception class to store some additional info:
public class MyException : Exception
{
public int ErrorCode{get;set;}
public MyException()
{}
}
In the above example, the ErrorCode value is stored in the exception, meaning that I have to add it to and retireve if from the SerializationInfo object in the protected constructor and the overridden GetObjectData method.
The Exception class has a Data property, which according to MSDN:
Gets a collection of key/value pairs that provide additional user-defined information about the exception.
If I store the error code inside the Data, it will get serialised for me by the Exception class (according to Reflector), meaning that my exception class now looks like:
public class MyException : Exception
{
public int ErrorCode
{
get {return (int) Data["ErrorCode"];}
set {Data["ErrorCode"] = value;}
}
public MyException()
{}
}
This means that whilst there is a bit more work to do in dealing with the get/set of the error code (like dealing with casting errors and situations where the error code might not be in the dictionary), I don't have to worry about serialising/deserialising it.
Is this just two different ways of achieving the same thing, or does one way have any clear advantage(s) over the other (apart from those I've already mentioned)?
If you are bothering to create your own exception, you don't need the Data property. Data comes in useful when you want to store a bit of extra information in an existing exception class, but don't want to create your own custom exception class.
I would avoid using Data as it is not under your control e.g. some code somewhere might decide to overwrite the "ErrorCode" value. Instead use the propery and implement serialization. I use the following code to test all my custom exceptions to make sure I've implemented them properly.
public static void TestCustomException<T>() where T : Exception
{
var t = typeof(T);
//Custom exceptions should have the following 3 constructors
var e1 = (T)Activator.CreateInstance(t, null);
const string message = "message";
var e2 = (T)Activator.CreateInstance(t, message);
Assert.AreEqual(message, e2.Message);
var innerEx = new Exception("inner Exception");
var e3 = (T)Activator.CreateInstance(t, message, innerEx);
Assert.AreEqual(message, e3.Message);
Assert.AreEqual(innerEx, e3.InnerException);
//They should also be serializable
var stream = new MemoryStream();
var formatter = new BinaryFormatter();
formatter.Serialize(stream, e3);
stream.Flush();
stream.Position = 0;
var e4 = (T)formatter.Deserialize(stream);
Assert.AreEqual(message, e4.Message);
Assert.AreEqual(innerEx.ToString(), e4.InnerException.ToString());
}
Microsoft's own guidelines:
Do make exceptions serializable. An exception must be serializable to work correctly across application domain and remoting boundaries.
I would store it in the Data-property which sadly would let outside code modify the value without consent, or use solution 1 (in your example) but make it serializeable. In the end I would probably go for solution 1 so I can be sure that the value never changes.
You should go with the first solution. I can't see much value in the Data property, unless you plan to raise row Exception instances with attached infos.
If you have your own Exception type, then use properties instead: it's more clean and safe.