Dynamic Object Serialization - c#

I tried to serialize a DynamicObject class with BinaryFormatter, but:
Output file is too big, not exactly wire-friendly
Circular References not handled (stuck while serializing)
Since serializing a DynamicObject means very little by itself, here's the class I tried to serialize:
[Serializable()]
class Entity
: DynamicObject, ISerializable
{
IDictionary<string, object> values = new Dictionary<string, object>();
public Entity()
{
}
protected Entity(SerializationInfo info, StreamingContext ctx)
{
string fieldName = string.Empty;
object fieldValue = null;
foreach (var field in info)
{
fieldName = field.Name;
fieldValue = field.Value;
if (string.IsNullOrWhiteSpace(fieldName))
continue;
if (fieldValue == null)
continue;
this.values.Add(fieldName, fieldValue);
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
this.values.TryGetValue(binder.Name, out result);
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
this.values[binder.Name] = value;
return true;
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
foreach (var kvp in this.values)
{
info.AddValue(kvp.Key, kvp.Value);
}
}
}
(I guess I could have used an ExpandoObject, but that's another story.)
Here's a simple test program:
static void Main(string[] args)
{
BinaryFormatter binFmt = new BinaryFormatter();
dynamic obj = new Entity();
dynamic subObj = new Entity();
dynamic obj2 = null;
obj.Value = 100;
obj.Dictionary = new Dictionary<string, int>() { { "la la la", 1000 } };
subObj.Value = 200;
subObj.Name = "SubObject";
obj.Child = subObj;
using (var stream = new FileStream("test.txt", FileMode.OpenOrCreate))
{
binFmt.Serialize(stream, obj);
}
using (var stream = new FileStream("test.txt", FileMode.Open))
{
try
{
obj2 = binFmt.Deserialize(stream);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
Console.ReadLine();
}
Putting some breakpoints here and there helped me have a look at obj2 contents and it looks like the original data is correctly deserialized, though with the above shortcomings if you get imaginative and move data around.
I had a look at Marc Gravell's protobuf-net, but I'm not really sure how to use it in such a context (I'm not even sure I picked up the right version from the repository, but hey).
I know it's more code than words, but I don't think I can explain the scenario any better. Please do tell if there's something I can add to make this question clearer.
Any help is much appreciated.

I'm 98% certain that this sequence will work for a dynamic object.
convert object to an Expando Object
cast expando object to be of type Dictionary
use ProtoBuf-net Serializer.Serialize / .Deserialize as per normal
convert dictionary to Expando Object
You can convert objects to a collection of name/value pairs for transfering.
That's just a small subset of what dynamic can do, but perhaps it is enough for you.
There's some custom code to handle some of the conversions above that I can show you if there's interest.
I don't have a solution for when dynamic is a placeholder to a class. For this case I'd suggest getting the type and using a switch statement to serialize / deserialize as you require. For this last case, you'd need to place a something to indicate which type of generic deserialization that you need (string / id / fully qualified type name / etc). Assumption is that you are dealing with a list of expected types.
Note: Expando implements IDictionary. An Expando is merely merely a list of key/value pairs. ie. the thing you dot into is the key, and the value is the return from whatever chain of functions implements that. There are a set of dynamic interfaces for customising the syntactic sugar experience, but most of the time you wont to look at them.
refs:
Dictionary from IDictionary using the constructor -- http://msdn.microsoft.com/en-us/library/et0ke8sz(v=vs.110).aspx
IDictionary/Dictionary to Expando -- http://theburningmonk.com/2011/05/idictionarystring-object-to-expandoobject-extension-method/

I am not sure if JSON would be acceptable in your senario, but if it is I have used Json.net (http://json.codeplex.com) to serialize a dynamic types. It works quite well, it is fast, and the output is small in size. While Json.net doesn't return dynamic objects directly, it is very easy to convert the deserialized output of Json.Net to any dynamic type. In the example below I am using ExpandoObject as my dynamic type. The code below is what I have used in the Facebook Graph Toolkit. See this link for the original source: http://facebookgraphtoolkit.codeplex.com/SourceControl/changeset/view/48442#904504
public static dynamic Convert(string s) {
object obj = Newtonsoft.Json.JsonConvert.DeserializeObject(s);
if (obj is string) {
return obj as string;
} else {
return ConvertJson((JToken)obj);
}
}
private static dynamic ConvertJson(JToken token) {
// FROM : http://blog.petegoo.com/archive/2009/10/27/using-json.net-to-eval-json-into-a-dynamic-variable-in.aspx
// Ideally in the future Json.Net will support dynamic and this can be eliminated.
if (token is JValue) {
return ((JValue)token).Value;
} else if (token is JObject) {
ExpandoObject expando = new ExpandoObject();
(from childToken in ((JToken)token) where childToken is JProperty select childToken as JProperty).ToList().ForEach(property => {
((IDictionary<string, object>)expando).Add(property.Name, ConvertJson(property.Value));
});
return expando;
} else if (token is JArray) {
List<ExpandoObject> items = new List<ExpandoObject>();
foreach (JToken arrayItem in ((JArray)token)) {
items.Add(ConvertJson(arrayItem));
}
return items;
}
throw new ArgumentException(string.Format("Unknown token type '{0}'", token.GetType()), "token");
}

First off, the size of your file depends on 2 things (if I understand how BinaryFormatter works, please correct me if I'm wrong):
The size of the actual values being serialized, and
The names used to serialize the object's values with the SerializationInfo.AddValue method, which are stored in the output file so values can be used during deserialization with the same name.
Obviously, #1 is going to cause your biggest slowdown, which can only be reduced by optimizing the objects you're trying to serialize.
Because you're using dynamic objects, the almost unnoticably small size increase caused by #2 is unavoidable. If you knew the types and names of the object's members ahead of time, you could just give each member of the object very short, sequentially-determined name ("1", "2", "3", etc.) as you iterated over the object's members, adding them via SerializationInfo.AddValue. Then, during deserialization, you could use SerializationInfo.GetValue with the same sequentially-determined name, and deserialization would work just fine, regardless of the actual names of the values being deserialized, as long as you iterated through the object's members in the same order they were added in. Granted, this might only save you an average of 4 or 5 bytes per member, but those little amounts can add up in large objects.
#Raine: (I guess I could have used an ExpandoObject, but that's another story.)
Not so; I changed your code sample to use ExpandoObject instead of your Entity class, and got a SerializationException thrown at me. ExpandoObject is not marked with a SerializableAttribute, and it doesn't have the appropriate constructors to be deserialized or serialized. However, this doesn't mean you can't use ExpandoObject if you really want to: it implements IDictionary<string, object>, which in turn implements ICollection<KeyValuePair<string, object>>. Thus, an ExpandoObject instance is a collection of KeyValuePair<string, object> instances, which are marked as serializable. So, you could serialize an ExpandoObject, but you'd have to cast it as ICollection<KeyValuePair<string, object>> and serialize each KeyValuePair<string, object> in it individually. This would pointless, though, in terms of optimizing your original code sample, because it takes just as much file space.
In summary, I really don't think there's any way you could optimize serializing a dynamic object- you have to loop through the object's members every time it's serialized, and you have no way to know the object's size beforehand (by definition of dynamic).

I don't know if SharpSerializer supports Dynamic Objects but it might be worth a try:
http://www.sharpserializer.com/en/index.html

One Suggestion for serializing dynamic object is convert them to String and then serialize, you can then deserialize back to your object, if applicable in your case.

Related

How to check if T is a list of objects in a generic method

I am trying to write a generic method for deserializing from json file(s) with Json.NET
I want to be able to support deserializing files that contain objects and also arrays of objects. Below are simplified versions of the two generic methods I have at the moment:
/// <summary> Deserializes object or an array of objects from a list of files. </summary>
public static List<T> Deserialize<T>(List<string> filePathsList)
{
var result = new List<T>();
foreach (var file in filePathsList)
// HOW DO I FIND OUT IF T IS A LIST HERE?
// Resharper says: the given expression is never of the provided type
if (typeof(T) is List<object>)
{
var deserialized = Deserialize<List<T>>(file);
result.AddRange(deserialized);
}
// Resharper says: Suspicious type check: there is not type in the solution
// which is inherited from both 'System.Type' and 'System.Collections.IList'
else if (typeof(T) is IList)
{
// deserializing json file with an array of objects
var deserialized = Deserialize<List<T>>(file);
result.AddRange(deserialized);
}
else
{
// deserializing a single object json file
var deserialized = Deserialize<T>(file);
result.Add(deserialized);
}
return result;
}
/// <summary> Deserializes object or an array of objects from a file. </summary>
public static T Deserialize<T>(string filepath)
{
return JsonConvert.DeserializeObject<T>(File.ReadAllText(filepath));
}
The problem is, I need to know if the T is an object or a List of objects, before deserializing. How do I check for that inside the generic method? Because resharper gives me warnings and I can't seem to figure this out.
Edit: I made a mistake in the example code, as #Medo42 points out, it would call Deserialize() with a List<List<Something>>
Also, I should not have included an example involving the json serialization at all, it should have been more generic. The question is about finding out if T is a list of objects.
Thanks in advance for any help.
This is not a complete answer, but it's too long for a comment and might help you understand some of the issues better.
// Resharper says: the given expression is never of the provided type
if (typeof(T) is List<object>)
And Resharper is right. The is operator checks whether the instance on the left is of the type on the right, so in your case it checks if typeof(T) is an instance of List<object>. However, typeof(T) returns a Type instance which represents the type of T. The correct way to check (if you are after the exact type) would be
if (typeof(T) == typeof(List<object>))
But note that this will only apply if T is exactly List<object>. If it is also OK to have a subtype of List<object>, the line would be
if (typeof(List<object>).IsAssignableFrom(typeof(T)))
But your problems don't end there. You seem to assume that List<object> is a supertype of all lists. This is not the case, even if we can assume that we will only ever work with the List<T> implementation for lists. The reson for this is that List<T> is invariant.
Invariance means that a list of cats is not a list of mammals. If this seems counterintuitive, that's because you think of a list as a fixed collection that you want to read from. However, you can also add new items to a C# list, and if you were allowed to treat a List<Cat> as a List<Mammal> you could end up trying to add an elephant to that list, and this would cause no end of confusion to anyone else still holding a reference to that list as a List<Cat>.
For a solution to the type checking problem, I think drf's comment to dotctor's answer is the cleanest way to do what you think you want to do:
typeof(T).GetGenericTypeDefinition() == typeof(List<>)
As a final aside, the following code also looks wonky:
var deserialized = Deserialize<List<T>>(file);
You do this after figuring out that T is really a List<Something>, so you're now trying to deserialize your file as a List<List<Something>>, which is probably not what you want.
You can check it easily
if (typeof(T).Name == "List`1")
{
// T is a generic list
}
As mentioned by drf a better way which does not rely on internal implementations is:
if (typeof(T).GetGenericTypeDefinition() == typeof(List<>))
{
// T is a generic list
}
You dont need this, you can simplify your code just using LINQ!!!
/// <summary>
/// Deserializes object or an array of objects from a list of files.
/// </summary>
public static List<T> Deserialize<T>(List<string> filePathsList)
{
return filePathsList
.Select(System.IO.File.ReadAllText)
.Select(JsonConvert.DeserializeObject<T>)
.ToList();
}
#Hamid Pourjam's answer is good, but throw an exception for non-generic types, so you should check IsGenericType too. here is helper method for doing that.
public bool IsList(object o)
{
if (o == null) return false;
var type = o.GetType();
return o is IList && type.IsGenericType && type.GetGenericTypeDefinition().IsAssignableFrom(typeof(List<>));
}
Usage:
public class Foo
{
public string Key { get; set; }
}
// #1
var foo = new Foo { Key = "value" };
// #2
var foos = new List<Foo>();
foos.Add(foo);
// #3
var lst = new List<object>();
lst.Add(new { Name = "John" });
IsList(foo); // false
IsList(foos); // true
IsList(lst); // true

Converting a KeyValuePair collection in to anonymous type

Is it possible to convert a a IEnumerable<KeyValuePair<string,string>> of KeyValuePair to an anonymous type?
Dictionary<string, string> dict= new Dictionary<string, string>();
dict.add("first", "hello");
dict.add("second", "world");
var anonType = new{dict.Keys[0] = dict[0], dict.Keys[1] = dict[1]};
Console.WriteLine(anonType.first);
Console.WriteLine(anonType.second);
********************output*****************
hello
world
The reason i would like to do this is because I am retrieving an object from a webservice that represents an object that does not exist in the wsdl. The returned object only contains a KeyValuePair collection that contains the custom fields and their values. These custom fields can be named anything, so i cant really map an xml deserialization method to the final object i will be using (whose properties must be bound to a grid).
*Just because I used Dictionary<string,string> does not mean it is absolutely a dictionary, i just used it for illustration. Really its an IEnumerable<KeyValuePair<string,string>>
Ive been trying to thing of a way to do this, but am drawing a blank. This is c# .NET 4.0.
You could use the ExpandoObject, it is based on a dictionary.
I think there are a lot of ways to achieve this, but actually converting it in the same Dictionary seems a bit odd to do.
One way to accomplish this, by not actually converting everyting is the following:
public class MyDictionary<T,K> : Dictionary<string,string> // T and K is your own type
{
public override bool TryGetValue(T key, out K value)
{
string theValue = null;
// magic conversion of T to a string here
base.TryGetValue(theConvertedOfjectOfTypeT, out theValue);
// Do some magic conversion here to make it a K, instead of a string here
return theConvertedObjectOfTypeK;
}
}
ExpandoObject is the best option, which I believe is a wrapper around some XML. You could also use an XElement:
var result = new XElement("root");
result.Add(new XElement("first", "hello"));
result.Add(new XElement("second", "world"));
Console.WriteLine(result.Element("first").Value);
Console.WriteLine(result.Element("second").Value);
foreach (var element in result.Elements())
Console.WriteLine(element.Name + ": " + element.Value);
I haven't used ExpandoObject, so I'd try that first because I understand it does exactly what you want and is also something new and interesting to learn.

How do I reflect over the members of dynamic object?

I need to get a dictionary of properties and their values from an object declared with the dynamic keyword in .NET 4? It seems using reflection for this will not work.
Example:
dynamic s = new ExpandoObject();
s.Path = "/Home";
s.Name = "Home";
// How do I enumerate the Path and Name properties and get their values?
IDictionary<string, object> propertyValues = ???
In the case of ExpandoObject, the ExpandoObject class actually implements IDictionary<string, object> for its properties, so the solution is as trivial as casting:
IDictionary<string, object> propertyValues = (IDictionary<string, object>)s;
Note that this will not work for general dynamic objects. In these cases you will need to drop down to the DLR via IDynamicMetaObjectProvider.
There are several scenarios to consider.
First of all, you need to check the type of your object. You can simply call GetType() for this.
If the type does not implement IDynamicMetaObjectProvider, then you can use reflection same as for any other object. Something like:
var propertyInfo = test.GetType().GetProperties();
However, for IDynamicMetaObjectProvider implementations, the simple reflection doesn't work. Basically, you need to know more about this object. If it is ExpandoObject (which is one of the IDynamicMetaObjectProvider implementations), you can use the answer provided by itowlson. ExpandoObject stores its properties in a dictionary and you can simply cast your dynamic object to a dictionary.
If it's DynamicObject (another IDynamicMetaObjectProvider implementation), then you need to use whatever methods this DynamicObject exposes. DynamicObject isn't required to actually "store" its list of properties anywhere. For example, it might do something like this (I'm reusing an example from my blog post):
public class SampleObject : DynamicObject
{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = binder.Name;
return true;
}
}
In this case, whenever you try to access a property (with any given name), the object simply returns the name of the property as a string.
dynamic obj = new SampleObject();
Console.WriteLine(obj.SampleProperty);
//Prints "SampleProperty".
So, you don't have anything to reflect over - this object doesn't have any properties, and at the same time all valid property names will work.
I'd say for IDynamicMetaObjectProvider implementations, you need to filter on known implementations where you can get a list of properties, such as ExpandoObject, and ignore (or throw an exception) for the rest.
If the IDynamicMetaObjectProvider can provide the dynamic member names, you can get them. See GetMemberNames implementation in the apache licensed PCL library Dynamitey (which can be found in nuget), it works for ExpandoObjects and DynamicObjects that implement GetDynamicMemberNames and any other IDynamicMetaObjectProvider who provides a meta object with an implementation of GetDynamicMemberNames without custom testing beyond is IDynamicMetaObjectProvider.
After getting the member names it's a little more work to get the value the right way, but Impromptu does this but it's harder to point to just the interesting bits and have it make sense. Here's the documentation and it is equal or faster than reflection, however, unlikely to be faster than a dictionary lookup for expando, but it works for any object, expando, dynamic or original - you name it.
Requires Newtonsoft Json.Net
A little late, but I came up with this. It gives you just the keys and then you can use those on the dynamic:
public List<string> GetPropertyKeysForDynamic(dynamic dynamicToGetPropertiesFor)
{
JObject attributesAsJObject = dynamicToGetPropertiesFor;
Dictionary<string, object> values = attributesAsJObject.ToObject<Dictionary<string, object>>();
List<string> toReturn = new List<string>();
foreach (string key in values.Keys)
{
toReturn.Add(key);
}
return toReturn;
}
Then you simply foreach like this:
foreach(string propertyName in GetPropertyKeysForDynamic(dynamicToGetPropertiesFor))
{
dynamic/object/string propertyValue = dynamicToGetPropertiesFor[propertyName];
// And
dynamicToGetPropertiesFor[propertyName] = "Your Value"; // Or an object value
}
Choosing to get the value as a string or some other object, or do another dynamic and use the lookup again.
Simple solution to only reflect over json objects:
using System.Collections.Generic;
using System.Text.Json;
dynamic d = new {a = 1, b = 2, c = 3};
foreach ((string k, object o) in JsonSerializer.Deserialize<Dictionary<string, object>>(JsonSerializer.Serialize(d)))
{
}

Generic method to recive any type of object and convert the object to a List<string>

EDIT AGAIN: the solution was probably different from my original question. Thanks everyone very much your great ideas. I wish I could vote for more than one answer.
EDIT: I am populating a Jquery table plugin from datatables/.net and it requires the data (Json) to be in a certain format like this;
"sEcho": 1,
"iTotalRecords": 57,
"iTotalDisplayRecords": 57,
"aaData": [
[
"Gecko",
"Firefox 1.0",
"Win 98+ / OSX.2+",
"1.7",
"A"
],
[
"Gecko",
"Firefox 1.5",
"Win 98+ / OSX.2+",
"1.8",
"A"
],
...
]
}
I am recieving data from a service that is returning a collection of object. I would like one method which I can pass these collections into and it will return the appropriate string
thanks
END EDIT
I would like to build a method that can receive and object that we build and will return an array List each containing the value of each object passed in. For example;
I have a collection of 'Car' objects
What I would like to do is
public object[] Something<T>(_cars)
{
object[] objArray = new object[_cars.Count];
foreach(Car _car in _cars ){
IList objList = new List<string>;
objList.Add(_car.Color);
objList.Add(_car.EngineSize);
//etc etc
objArray[i] = objList;//i'll have to use a for loop to get the i counter but you get my idea
}
return objArray
}
my problem is how can I access the properties of the object without knowing what type of object it is?
thanks for any help
Update: To answer your revised question - produce a JSON result of a data structure - use the built-in JavaScriptSerializer class:
JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = seriaizer.Serialize(myObjectOrArray);
Below is the previous answer.
how can I access the properties of the object without knowing what type of object it is
Using Reflection, and grabbing the properties which are strings. Note this is not necessarily a good idea. The fact that you have to use reflection to get what you want is usually a HUGE WARNING FLAG that your design is wrong.
However, in the hopes of learning something useful, here's how it could be done:
public object[] Something<T>(T[] items)
{
IList objList = new List<object>();
//get the properties on which are strings
PropertyInfo[] properties = typeof(T).GetProperties().Where(p => p.PropertyType == typeof(string));
foreach(T item in items)
{
IList stringList = new List<string>;
foreach(PropertyInfo property in properties)
{
objList.Add(property.GetValue(item, null) as string);
}
objList.Add(stringList);
}
}
return objList.ToArray();
}
A far, far better solution would be to require all the objects coming into this method to conform to some interface that requires them to provide their own string-formatted data. Or maybe take two steps back and ask for help on the underlying problem. This approach is fraught with problems. It's a rabbit hole you don't want to go down.
Use the System.Web.Script.Serialization.JavaScriptSerializer class. It was specifically provided for JSON serialization.
using System.Web.Script.Serialization;
public string ToJson(object o)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(o);
}
EDIT: Oops, I missed that your plugin doesn't want a true JSON representation of the objects; it just wants arrays of values. You could use reflection to iterate over the properties of the objects as others have suggested, but then you have no control over which properties end up in which columns. It is not clear from your question whether that is a problem for you.
If you need a strict mapping between properties and columns, then you will have to define that somehow in C#. To do this you could implement IEnumerable as Ed demonstrates or create a custom interface:
public interface ITableDataSource
{
IList<string> GetTableData();
}
Then implement this on any objects that might need to be data sources for the jQuery table plugin:
public class Car : ITableDataSource
{
//...class implementation details...
public IList<string> GetTableData()
{
return new List<string>()
{
this.Color,
this.EngineSize,
this.NumberOfSeats.ToString()
};
}
}
Finally, in your method that is returning the data to the jQuery plugin, use the interface to construct your response object, then pass it to my ToJson() method to serialize it:
public string DoSomething(IList<ITableDataSource> objects)
{
var result = new
{
sEcho = 1,
iTotalRecords = 1,
iTotalDisplayRecords = 1,
aaData = new List<IList<string>>()
};
foreach (ITableDataSource ds in objects)
result.aaData.Add(ds.GetTableData());
return ToJson(result);
}
While it would be relatively straightforward to use reflection to loop through all of your objects and all the properties on those objects to build that string, it's already been written.
I would highly recommend looking at the Json.NET project found here. Add this DLL to your project and converting a list of objects into a Json formatted string is as easy as:
string json = Newtonsoft.Json.JsonConvert.SerializeObject( listOfCars );
IList objList = new List<string>();
foreach ( PropertyInfo prop in _car.GetType().GetProperties() )
{
var value = prop.GetValue( _car, null );
objList.Add( value != null ? value.ToString() : null );
}
objArray[i] = objList;
The code to get the Property values of an object is
foreach (PropertyInfo info in myObject.GetType().GetProperties())
{
if (info.CanRead)
{
object o = propertyInfo.GetValue(myObject, null);
}
}
my problem is how can I access the properties of the object without knowing what type of object it is?
Well, in the general sense you can't. Generics is all about treating objects generically. However, you can impose type constraints by using a where clause. Based on the foreach loop I would say constrain your types to types that implement IEnumerable, but then you go on to use properties like "Color" and "EngineSize", which are very specific. I don't even know why you would have properties named "Color" and "EngineSize" that are strings, but that is another problem altogether...
It seems like the best approach for you would be to define an interface or an abstract base class that each of these objects inherits from. Then you can use the 'where' clause to constrain to objects of that interface/base class only So...
public object[] Something<T>( T _cars) where T : IEnumerable<MyInterface>
However, if we are going to go down this road I don't see why the method should be generic at all. It could simply take an IEnumerable<T> as an input. When we only want to use one type in a method generics is not needed.

How to perform a deep copy of an object not marked as serializable (in C#)?

I am attempting to create a Clipboard stack in C#. Clipboard data is stored in System.Windows.Forms.DataObject objects. I wanted to store each clipboard entry (IDataObject) directly in a Generic list. Due to the way Bitmaps (seem to be) stored I am thinking I need to perform a deep copy first before I add it to the list.
I attempted to use Binary serialization (see below) to create a deep copy but since System.Windows.Forms.DataObject is not marked as serializable the serialization step fails. Any ideas?
public IDataObject GetClipboardData()
{
MemoryStream memoryStream = new MemoryStream();
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, Clipboard.GetDataObject());
memoryStream.Position = 0;
return (IDataObject) binaryFormatter.Deserialize(memoryStream);
}
I wrote the code below for another question and maybe it could come in useful for you in this scenario:
public static class GhettoSerializer
{
// you could make this a factory method if your type
// has a constructor that appeals to you (i.e. default
// parameterless constructor)
public static void Initialize<T>(T instance, IDictionary<string, object> values)
{
var props = typeof(T).GetProperties();
// my approach does nothing to handle rare properties with array indexers
var matches = props.Join(
values,
pi => pi.Name,
kvp => kvp.Key,
(property, kvp) =>
new {
Set = new Action<object,object,object[]>(property.SetValue),
kvp.Value
}
);
foreach (var match in matches)
match.Set(instance, match.Value, null);
}
public static IDictionary<string, object> Serialize<T>(T instance)
{
var props = typeof(T).GetProperties();
var ret = new Dictionary<string, object>();
foreach (var property in props)
{
if (!property.CanWrite || !property.CanRead)
continue;
ret.Add(property.Name, property.GetValue(instance, null));
}
return ret;
}
}
However I don't think this will be the final solution to your problem though it may give you a place to start.
Look up the docks for Serializable and find the stuff about serialization helpers. You can wrap the bitmap in your own serialization code the integrates with the .net framework.
Copy of my answer to: difference between DataContract attribute and Serializable attribute in .net
My answer fits much better here than there, although above question ends with:
"... or maybe a different way of creating a deepclone?"
I once did some inspection to an object structure via Reflection to find all assemblies required for deserialization and serialize them alongside for bootstrapping.
With a bit of work one could build a similar method for deep copying. Basically you need a recursive method that carrys along a Dictionary to detect circular references. Inside the method you inspect all fields about like this:
private void InspectRecursively(object input,
Dictionary<object, bool> processedObjects)
{
if ((input != null) && !processedObjects.ContainsKey(input))
{
processedObjects.Add(input, true);
List<FieldInfo> fields = type.GetFields(BindingFlags.Instance |
BindingFlags.Public | BindingFlags.NonPublic );
foreach (FieldInfo field in fields)
{
object nextInput = field.GetValue(input);
if (nextInput is System.Collections.IEnumerable)
{
System.Collections.IEnumerator enumerator = (nextInput as
System.Collections.IEnumerable).GetEnumerator();
while (enumerator.MoveNext())
{
InspectRecursively(enumerator.Current, processedObjects);
}
}
else
{
InspectRecursively(nextInput, processedObjects);
}
}
}
}
To get it working you need to add an output object and something like System.Runtime.Serialization.FormatterServices.GetUninitializedObject(Type type) to create the most shallowest copy (even without copying references) of each field's value. Finally you can set each field with something like field.SetValue(input, output)
However this implementation does not support registered event handlers, which is _un_supported by deserializing, too. Additionally each object in the hierarchy will be broken, if its class' constructor needs to initialize anything but setting all fields. The last point only work with serialization, if the class has a respective implementation, e.g. method marked [OnDeserialized], implements ISerializable,... .

Categories