How to find object position in the serialized generic list - c#

For I can have direct access to a particular object in a serialized generic list, I need to know position of it from de-serialized stream.
private static void Serialze(object obj, FileStream Stream)
{
BinaryFormatter bin = new BinaryFormatter();
bin.FilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Low;
bin.Serialize(Stream, obj);
}
private static object DeSerialize(FileStream Stream)
{
if (Stream.Position >= Stream.Length) return null;
BinaryFormatter bin = new BinaryFormatter();
bin.FilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Low;
object x = bin.Deserialize(Stream);
return x;
}
Suppose I have a generic list like this:
List<MyClass> L1=new List<MyClass>();
How can I to find position of L1[10] in my FileStreem, for using it, in DeSerialize method?

The format that BinaryFormatter uses is not seekable. You cannot extract sub-objects.
Probably, this question is an instance of the XY-Problem. Tell us what you want to achieve and why you need this. As asked, there is no answer.
Maybe you can make use of a database instead. Or, use Protocol Buffers, which are more flexible.

Related

Deep Copy using Reflection in an Extension Method for Silverlight?

So I'm trying to find a generic extension method that creates a deep copy of an object using reflection, that would work in Silverlight. Deep copy using serialization is not so great in Silverlight, since it runs in partial trust and the BinaryFormatter does not exist. I also know that reflection would be faster then serialization for cloning.
It would be nice to have a method that works to copy public, private and protected fields, and is recursive so that it can copy objects in objects, and that would also be able to handle collections, arrays, etc.
I have searched online, and can only find shallow copy implementations using reflection. I don't understand why, since you can just use MemberwiseClone, so to me, those implementations are useless.
Thank You.
For data contract objects we have used the following helper method for deep cloning within Silverlight:
public static T Clone<T>(T source)
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, source);
ms.Seek(0, SeekOrigin.Begin);
return (T)serializer.ReadObject(ms);
}
}
Used like this:
var clone = CloneHelper.Clone<MyDTOType>(dtoVar);
Required Namespaces:
using System.Reflection;
using System.Collections.Generic;
Method:
private readonly static object _lock = new object();
public static T cloneObject<T>(T original, List<string> propertyExcludeList)
{
try
{
Monitor.Enter(_lock);
T copy = Activator.CreateInstance<T>();
PropertyInfo[] piList = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (PropertyInfo pi in piList)
{
if (!propertyExcludeList.Contains(pi.Name))
{
if (pi.GetValue(copy, null) != pi.GetValue(original, null))
{
pi.SetValue(copy, pi.GetValue(original, null), null);
}
}
}
return copy;
}
finally
{
Monitor.Exit(_lock);
}
}
This is not specific to Silverlight in any way - it is just plain Reflection.
As written it will only work with objects that have a parameterless constructor. To use objects that require constructor parameters, you will need to pass in an object[] with the parameters, and use a different overload of the Activator.CreateInstance method e.g.
T copy = (T)Activator.CreateInstance(typeof(T), initializationParameters);
The propertyExcludeList parameter is a list of property names that you wish to exclude from the copy, if you want to copy all properties just pass an empty list e.g.
new List<string>()
Can't you just use regular .NET reflection? Serialize your object to a MemoryStream and then deserialize it back. This will create a deep copy (ultimately using reflection) and will require hardly any code on your part:
T DeepCopy<T>(T instance)
{
BinaryFormatter formatter=new BinaryFormatter();
using(var stream=new MemoryStream())
{
formatter.Serialize(stream, instance);
stream.Position=0;
return (T)formatter.Deserialize(stream);
}
}

Serialization in .NET

My task was to serialize and deserialize an object.
I want to know:
Whether my object is serialized in the way I'm doing it
How I get to know that my object is being serialized or deserialized
Instead of passing the object in the Serialize Method, I am passing object.properties. Does this affect it in any way?
FileStream fs = new FileStream(#"D:\Rough Work\Serialization\Serialization\bin\Debug\Log.txt",FileMode.OpenOrCreate);
Laptop obj = new Laptop();
obj.Model = 2;
obj.SerialNumber = 4;
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, obj.Model);
formatter.Serialize(fs, obj.SerialNumber);
[Serializable]
class Laptop
{
public int Model;
public int SerialNumber;
}
If you can successfully deserialize an object then you serialized it correctly.
You don't need to serialize the properties individually. You can just serialize the entire object and deserialize it the same way.
using (var fs = new FileStream(#"D:\Rough Work\Serialization\Serialization\bin\Debug\Log.txt",FileMode.OpenOrCreate))
{
var formatter = new BinaryFormatter();
formatter.Serialize(fs, obj);
}
using (var fs = new FileStream(#"D:\Rough Work\Serialization\Serialization\bin\Debug\Log.txt",FileMode.OpenOrCreate))
{
var formatter = new BinaryFormatter();
obj = formatter.Deserialize(fs) as Laptop;
}
If your question is how would Laptop class know that it is being serialized then you might want to implement ISerializable interface.
See BinaryFormatter.Deserialize
You can convert to serialised method to a string and output it to the debug window
I want to know:
Whether my object is serialized in the way I'm doing it
Then you can use xml serialization, that way you can check your serialized object since it will be in human-readable form.

How do I clone an ancestor in c#?

I need a semi-shallow copy of an object. Under my original design I used MemberwiseClone to catch all the simple stuff and then I specifically copied the classes to the extent that they needed to be copied. (Some of them are inherently static and most of the rest are containers holding static items.) I didn't like the long list of copies but there's no way around that.
Now, however, I find myself needing to create a descendent object--do I now have to go back and copy all those fields that previously I was copying with MemberwiseClone?
Or am I missing some better workaround for this?
The easiest way to clone, I find, is to use serialization. This obviously only works with classes that are [Serializable] or that implement ISerializable.
Here is a general generic extension you can use to make any serializable class' objects cloneable:
public static T Clone<T>(this T source)
{
if (source == default(T))
{
return default(T);
} else {
IFormatter formatter = new BinaryFormatter();
Stream ms = new MemoryStream();
using (ms)
{
formatter.Serialize(ms, source);
stream.Seek(0, SeekOrigin.Begin);
return (T) formatter.Deserialize(ms);
}
}
}

How to send a XmlSerializer Class to a WebService and then Deserialize it?

I want to be able to send a XmlSerializer class (which is generated obvious in remote C# application) over a WebService that will then deserialize it into a class. (I didnt know it its possible either)
My class is:
SystemInfo
I'm serializing it this way:
XmlSerializer mySerializer = new XmlSerializer(typeof(SystemInfo));
StreamWriter myWriter = new StreamWriter(textBox1.Text);
mySerializer.Serialize(myWriter, sysinfo);
How can i build the WebService?
[WebMethod]
public void Reports(XmlSerializer xmlSerializer)
{
.
.
.
}
Can anyone help me out?
Regards
First I assume you want to pass arbitrary types to a single web method, where the types are shared by the client and the server.
There is not much point in sending the XmlSerializer, it only has the logic to serialize/deserialize. It does not have the actual data, that is either read/written to a stream. What you should do is pass either a string or and XmlNode.
The caller of the web service can then a client side instance of XmlSerializer and serialize the object to a string, then call the web method passing the string as an argument. The web method it self can then create an instance of a XmlSerializer and deserialize the string back into an object. Of course to create the server size instance of the serializer you will need to know the root type to create the serializer for, you can pass this as a type name and use Type.GetType() to get the correct type to pass to the XmlSerializer.
If you know upfront which types you are going to be passing then you could also declare your web method more strongly typed and explicitly create methods for the types you expect to recieve.
If the wire format is not too much of a concern, you could also user SoapFormatter or a BinaryFormatter to handle the serialization/deserialization. In the later case of the BinaryFormatter you would declare your web method to take a byte[] argument, the advantage of these formatters (serializers) is that they do not need additional info on the type when you create the instance of the formatter, but they can be slower than an XmlSerializer
Update: Added some simple examples (Untested)
Example using an XmlSerializer, here you will need to pass the type name from the client side, so I made it an additional argument.
[WebMethod]
public void Reports(string xml, string typeName)
{
XmlSerializer xs = new XmlSerializer(Type.GetType(typeName));
object obj = xs.Deserialize(new StringReader(xml));
// use the deserialize object
}
Example using a BinaryFormatter, no type name needed but you the class types will need to be serializable
[WebMethod]
public void Reports(byte[] data)
{
BinaryFormatter bf = new BinaryFormatter();
object obj = bf.Deserialize(new MemoryStream(data));
// use the deserialized object
}
On the client side you would use something like the following to serialize using the BinaryFormatter.
// initialize the SystemInfo instance that you want to pass to the server
SystemInfo si = new SystemInfo() { SystemName = "My System" };
// Serialize to a memory stream
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, si);
// Call the service, passing the array from the memory stream
ws.Reports(ms.ToArray());
Chris, thanks for helping me out. It was a major step forward.
I solved the problem sending the xml string:
SystemInfo sysinfo = new SystemInfo();
sysinfo.RUN();
XmlSerializer mySerializer = new XmlSerializer(typeof(SystemInfo));
MemoryStream memStream = new MemoryStream();
mySerializer.Serialize(memStream, sysinfo);
memStream.Seek(0, System.IO.SeekOrigin.Begin);
XmlDocument doc = new XmlDocument();
doc.Load(memStream);
memStream.Close();
localhost.WS_Agente dasdsa = new localhost.WS_Agente();
dasdsa.Reports(doc.InnerXml);
And the WebService:
[WebMethod]
public void Reports(string xml)
{
XmlSerializer mySerializer = new XmlSerializer(typeof(SystemInfo));
SystemInfo obj = (SystemInfo)mySerializer.Deserialize(new StringReader(xml));
}
Its working like a charm now :)
My question is: Can i improve the code?
Thanks

Problem in serializing

Presently I need to serialize one of my object which contains more my own classes object.
But the problem is I dont want to save it in a file and then retrieve it into memory stream.
Is there any way to directly serialize my object into stream.
I used BinaryFormatter for seializing.
First I used a MemoryStream directly to take serialize output but it is giving error
at time of deserialization. But later when I serialize it with a file then close it and
again reopen it , it works perfectly. But I want to take it direct into stream because
in my program I need to do it frequently to pass it into network client. And using file
repeatedly might slow down my software.
Hope I clear my problem. Any Sugetion ?
If you're trying to deserialize from the same MemoryStream, have you remembered to seek back to the beginning of the stream first?
var foo = "foo";
var formatter = new BinaryFormatter();
using (var stream = new MemoryStream())
{
// Serialize.
formatter.Serialize(stream, foo);
// Deserialize.
stream.Seek(0, SeekOrigin.Begin);
foo = formatter.Deserialize(stream) as string;
}
Here's a quick and dirty sample, of serializing back and forth a string. Is this what your trying to do?
static void Main(string[] args)
{
var str = "Hello World";
var stream = Serialize(str);
stream.Position = 0;
var str2 = DeSerialize(stream);
Console.WriteLine(str2);
Console.ReadLine();
}
public static object DeSerialize(MemoryStream stream)
{
BinaryFormatter formatter = new BinaryFormatter();
return formatter.Deserialize(stream);
}
public static MemoryStream Serialize(object data)
{
MemoryStream streamMemory = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(streamMemory, data);
return streamMemory;
}

Categories

Resources