I am in a situation I need to serialize only the values of the members of an object to a file.
for example, if the object contains 3 string members I would want the output of the serialization to be only this 3 strings without the serialization metadata the Binaryformatter adds, like the version, culture, and assembly name of the object.
One option is just to write each members of the object directly, but I want to avoid this because I have lots of classes that need to be serialize like this and I don't want to write a function that handles this differently for each class.
Requirements:
I want to be able to write to any type of file, I want the values of the members to be translated to bytes (into a buffer or directly into the file) and to be able to write those bytes at a specific position in the file.
Is there a way or an API of serializing only the value of the members of an object?
Matan,
Here is some code I put together for an entirely different purpose, but it takes an unknown object and serializes it into an XML file (updated to include better coding practices).
void objectToXMLFile(String fn, object o)
{
XmlTextWriter textWriter = new XmlTextWriter(fn, null);
System.Type type = o.GetType();
PropertyInfo[] piList = type.GetProperties();
textWriter.WriteStartDocument();
textWriter.WriteStartElement("attributeList");
foreach (PropertyInfo pi in piList)
{
textWriter.WriteStartElement("attribute");
textWriter.WriteStartElement("name");
textWriter.WriteString(pi.Name);
textWriter.WriteEndElement();
textWriter.WriteStartElement("value");
textWriter.WriteString(pi.GetValue(o).ToString());
textWriter.WriteEndElement();
textWriter.WriteStartElement("dataType");
textWriter.WriteString(pi.PropertyType.Name);
textWriter.WriteEndElement();
textWriter.WriteEndElement();
}
textWriter.WriteEndElement();
textWriter.WriteEndDocument();
textWriter.Close();
}
If you do end up using Reflection to only write the wanted properties, you may want to consider some performance implications.
Using Reflection is slow. Reflecting the type itself has a high price, and then dynamically invoking the PropertyInfo by calling PropertyInfo.GetValue is very slow.
An alternative is to build an Expression tree that calls the properties and writes their values, and then compile this expression into an Action. You can cache these Action instances in a dictionary keyed by the Type of the object you are serializing, and invoke the right one when you want to serialize the object.
That would be much much faster and will also not create so much load on the GC.
Another alternative you may consider is code generation at build time - you can generate a class to serialize your target type quickly and cheaply. In some scenarios this is a good choice.
Related
I'm trying to log model passed to controller by doing something like this:
_log
.ForContext("Id", "XXXXXX-XXXX-XXXX-XXXXXXXXX")
.ForContext("Email", email)
.ForContext("UserId", userId)
.ForContext("Parameters", parameters)
.ForContext("Errors", errors.ToArray())
.ForContext("ActionArguments", actionArguments)
.Information(message);
where actionArguments is of type IDictionary<string, object> actionArguments. This is interpreted like
{
someProperty: "Some.Namespace.Dtos.Something.MyTypeDto"
}
and I really wish someProperty to be expanded to what complex type represents. Is it possible? How to do it?
By default, Serilog will serialize objects with types it does not understand (including your own custom types) by just calling ToString() to get a simple representation. The default implementation of ToString() for an object just returns the full name of the type, which is why the type name of your DTO is showing up in the log context.
What you're after is called 'destructuring' in Serilog. In the documentation, this is defined as:
Destructuring is the process of taking a complex .NET object and converting it into a structure, which may later be represented as say, a JSON object or XML blob
There's an optional argument destructureObjects that you can provide to the ILogger.ForContext method that tells Serilog to try and pull out additional information from the object:
.ForContext("ActionArguments", actionArguments, destructureObjects: true)
By default it will destructure recursively using reflection, effectively walking down all of the object's properties and any properties of those properties, etc. until it finds a type that it knows how to format.
Just be careful that you're not logging any sensitive information by using this approach; Serilog will do its best to include every value it finds.
I've got a generic method that takes an arbitrary JObject (from JSON.net) and converts it into the generically typed object.
So, let's simplify my conversion method to look like the following:
private async Task<T> ConvertToObject(JObject obj) {
//Lots of other stuff yielding in the creation of newObj
var result = newObj.ToObject<T>();
return result;
}
Now this method works fine as-is, but I want to modify the method so I can properly do the same for complex properties within the generic object that aren't available in my JObject (e.g. I have to look them up separately, do this same conversion and apply to this object result).
My approach so far is to loop through all the properties, identify the complex types, perform the lookup to retrieve their values from my data store, then execute the above against them (potentially recursively if they too have any complex objects), then write that value back out to this complex property, repeat for any others and then as before, return that result.
I'm retrieving the properties via Reflection:
var properties = result.GetType().GetProperties();
foreach (var property in properties) {
if (IsSimple(property.PropertyType)
continue;
//Do external lookup
var convertedValue = new ConversionTool<>().Lookup(query);
}
Now, that last line is where I'm having my problem. I'm expected to pass a class name into this, not just a type, but I only know the type at runtime per the reflection methods above. I found a post at http://www.paulbatum.com/2008/08/less-fragile-way-to-invoke-generic.html detailing how to make this work if I were simply passing the generic type into a method and he explains the issue with using Activator.CreateInstance in the comments, but it seems like I know the type I'd want to put there - I just don't know it until it runs (and I retrieve it via reflection).
This seems like an issue that ORMs would run into when it comes to populating complex properties of their entities, but I'm having a difficult time finding how they're doing this.
Given that the caller of this method is aware at runtime what the intended type is, how might I go about passing that type into the generic class constructor so I might call it recursively for each complex member of a given type?
For this code snippet below, which probably won't need an explanation to the persons who can answer my question:
protected readonly List<TEntity> Records; //Within the class declared.
protected virtual void ReadFile()
{
//So the file exists, is not null and not whitespace only
var serializer = new XmlSerializer(Records.GetType());
using (var reader = new StringReader(contents))
{
var records = (List<TEntity>)serializer.Deserialize(reader);
Records.Clear();
Records.AddRange(records);
}
}
It's about the line:
var records = (List<TEntity>)serializer.Deserialize(reader);
(1) How could I've known (deduced) that this cast was possible? I looked up that the Deserialize() methods returns the type "object". So that's can't be the hint. (Edit: I mean during coding/design time. Not compiling afterwards for trial and error. So think goal-wise: goal = store xml data into a list<>. Is it possible through a simple cast (yes) and how could I have known in advance?).
(2) How could I've / can I deduce(d) how variable "records" would end up? For example, what shouldn't make me think that only a single entry is written to the list and that single index holds all of the XML content? (as opposed to keeping a nice structure whilst writing it to the list)
The final goal of my question is to understand when such a cast is needed and especially how the actual cast makes sense. I'm wiling to put in effort in it with practice and experimentations. But I don't know how to think.
a) I"m a beginner, though learning fast i.m.o.
b) I Have read and understood implicit/explicit casting and understood that it's based on range, as opposed to data size. But those tutorials restrict to built in basic types like int, float, decimal (you name it). Now this problem domain (casting) I would like to move to a higher level.
The cast
var records = (List<TEntity>)serializer.Deserialize(reader);
works because of
new XmlSerializer(Records.GetType());
The cast from object to anything will always compile but yield a runtime exception when the types don't match.
The serializer knows about the root type from its constructor and will create a result of that type. If the XML doesn't match that, it will throw an error. You cannot deserialze a single TEntity with this, only a List<> with 0 or more elements.
You can verify it easily:
object temp = serializer.Deserialize(reader);
// print or inspect temp.GetType() here
var records = (List<TEntity>)temp;
Note that if XmlSerialzier had been designed as a generic type then the cast would not have been necessary:
var serializer = new XmlSerializerGeneric<List<TEntity>>();
var records = serializer.Deserialize(reader);
But it wasn't, it uses the older way of 'dynamic typing' through the System.Object class.
It would be much obvious if instead of this
var serializer = new XmlSerializer(Records.GetType());
you used this
var serializer = new XmlSerializer(typeof(List<TEntity>));
The rule is simple. What ever type you pass to the XmlSerializer constructor, you can safely cast the Deserialize result to that type.
The cast is needed because XmlSerializer (as well as Enum and many other framework classes) exists from a long time before the generics were added, so returning an object is the only choice it had. And it must remain this way because of backward compatibility (to not break the existing code you have written).
How could I've known (deduced) that this cast was possible?
One way is to use the debugger. Put a breakpoint on the Records.Clear(); line just after records is set. Then in either the Watch window or the Locals window, take a look at the type of the records variable. It might say something like this:
object { List<TEntity> }
records is a List<TEntity> but it's being passed as an object because the call to serializer.Deserialize(reader) returns an object. And if you didn't declare an implicit conversion from object to List<TEntity>, you have to use an explicit conversion.
I recommend against implicit conversions for all but the most obvious cases.
(1) How could I've known (deduced) that this cast was possible?
It all began here,
protected readonly List<TEntity> Records;
You don't have to deduce but you already know you are reading file contents from a file which has some XML with some sort of structure and since you are using a list you know upfront that there are going to be mulitple list items
I looked up that the Deserialize() methods returns the type
"object". So that's can't be the hint.
object class is not used directly (So basically that is a hint that you have to cast) and it must be casted to some type (in this case List<TEntity>) before it could be used.
(2) How could I've / can I deduce(d) how variable "records" would end
up?
Lets say I want to create list of persons, I would know I would keep some structure for example,
I have following XML
<persons>
<person>
<name>Chuck Norris</name>
<age>137</age>
</person>
<person>
<name>Donald Trump</name>
<age>19</age>
</person>
<persons>
You know you want to get the records of person your list would be declare like this, List<Person>. You know Deserialize() method returns object and you would want to read persons data, you would cast that object into List<Person>. So basically what I am trying to say is that both the question you asked are based on the assumption and choices made at the design time of you application.
There must be an easier way...
void TransferFrom(object obj) {
foreach(PropertyInfo prop in this.GetType().GetProperties()) {
prop.SetValue(this, obj.GetType().GetProperty(prop.Name).GetValue(obj, null), null);
}
}
I have two separate libraries with the same object definition - all property names/types are the same. Is the above the only way to copy the values or is there another way? I'm unable to reference one of the dlls and the object to be copied is passed as an object rather than a distinct type.
If you have control over both assemblies, take a look at Data Contracts, which were designed specifically to do what you're describing.
AutoMapper is flexible and powerful. I'm not sure if it'll work without referencing both types, but it's something to consider.
I'm not sure, but if classes in both assemblies have the same type name, you can try to use XmlSerializer by serializing instance of type from assemlby A then deserialize instance of type from assembly B from the same stream.
While debugging an ASP.NET application, I want to get a print-out of the entire state of a very large object. I want all the properties and values in that object and the same for every object-property, recursively.
Because the front-end of the application times out after a significant delay, I can't add a watch or use the Immediate window or hover over the object, since there won't be adequite time to fully examine the object.
Is there a way of getting a complete printout of an object in debug mode, or say, a utility or a C# function that would do this?
You could use reflection to get the list of all properties and fields on the class type, then use that to get the runtime values of each of those properties / values and spit them to the console.
The PropertyInfo type (here) and FieldInfo type (here) are what you need to get from the Type object for your own class instance.
MyObject myObject = ... //setup my object
Type myType = myObject.GetType(); //or Type.GetType(myObject); //I think
PropertyInfo[] properties = myType.GetProperties();
FieldInfo[] fields = myType.GetFields();
properties[0].GetValue(myObject); //returns the value as an Object, so you may need to cast it afterwards.
Reflection really is your best bet here. You can start with your root object, get all of its properties and their values, and if necessary get the properties and values off of those values recursively. It's a really powerful technique, and if you don't know it yet you probably should learn it anyway, and this makes a perfect project to learn with. :)