Reputation: 279
I try to write my own serializer. But this serializer serializes only properties. How to serialize fields ? Classes which I have are shown below:
namespace MySerializer
{
class MySerializer
{
private Type targetType;
public MySerializer(Type targetType)
{
this.targetType = targetType;
if (!targetType.IsDefined(typeof(DataContractAttribute), false))
throw new Exception("No soup for you");
}
public void WriteObject(Stream stream, Object graph)
{
IEnumerable<PropertyInfo> serializbleProperties =
targetType.GetProperties().Where(p => p.IsDefined(typeof (DataMemberAttribute), false));
var writer = new StreamWriter(stream);
writer.WriteLine("<" + targetType.Name + ">");
foreach (PropertyInfo propInfo in serializbleProperties)
writer.Write("\t<" + propInfo.Name + ">" + propInfo.GetValue(graph, null) +
"</" + propInfo.Name + ">");
writer.WriteLine("</" + targetType.Name + ">");
writer.Flush();
}
}
}
[DataContract]
class Person
{
[DataMember]
public string _family;
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
[DataMember]
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
Person name = new Person
{
_family = "big",
FirstName = "Vasy",
LastName = "Bobrow",
Age = 20
};
MySerializer serializer = new MySerializer(name.GetType());
MemoryStream someRam = new MemoryStream();
serializer.WriteObject(someRam, name);
someRam.Seek(0, SeekOrigin.Begin);
Console.WriteLine(XElement.Parse(
Encoding.ASCII.GetString(someRam.GetBuffer()).Replace("\0", "")));
}
}
To serialize fields I can use FieldsInfo instead of PropetryInfo or there is another way?
Upvotes: 0
Views: 409
Reputation: 127543
This question really isn't about serialization, it is more about how to do reflection. If you want to return both Fields and Properties you need to use the method GetMembers
and specify that you are looking for properties and fields.
public void WriteObject(Stream stream, Object graph)
{
IEnumerable<MemberInfo> serializbleMembers =
targetType.GetMembers(BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic )
.Where(p => p.IsDefined(typeof (DataMemberAttribute), false));
var writer = new StreamWriter(stream);
writer.WriteLine("<" + targetType.Name + ">");
foreach (MemberInfo memberInfo in serializbleMembers)
{
writer.Write("\t<" + memberInfo.Name + ">");
var fieldInfo = memberInfo as FieldInfo;
if(fieldInfo != null)
{
writer.Write(fieldInfo .GetValue(graph, null).ToString());
}
var propInfo= memberInfo as PropertyInfo;
if(propInfo != null)
{
writer.Write(propInfo.GetValue(graph, null).ToString());
}
writer.Write("</" + memberInfo.Name + ">");
}
writer.WriteLine("</" + targetType.Name + ">");
writer.Flush();
}
However I doubt this your WriteObject method will be very useful, both your and my WriteObject
method relies on the .ToString()
value to be overridden (yours has a implicit .ToString()
when you do ">" +
whatever is on the right hand side of the +
has .ToString()
called on it for you). For example you tried to use your class on something like
[DataContract]
class Example
{
public Example()
{
ExampleArray = new int[] {1, 2};
}
[DataMember]
int[] ExampleArray {get; set;}
}
you would get
<Example>
<ExampleArray>System.Int32[]</ExampleArray >
</Example>
as your output because any class that has not had .ToString()
overridden just outputs .GetType().Name
.
Upvotes: 3