serialization multiple objects - c#

I'm trying to make an application that allows people to register their information so that employers could read them and contact them.
The problem is whenever I try to deserialize the information, I either get one object only, or the program throw an exception.
private void button1_Click(object sender, EventArgs e)
{
FileStream sw = new FileStream("Applicants.xml",FileMode.Append,FileAccess.Write,FileShare.None);
XmlSerializer xs = new XmlSerializer(typeof(Class1), new XmlRootAttribute("Applist"));
Class1 cc = new Class1();
cc.name = textBox1.Text;
cc.age = textBox2.Text;
cc.degree = textBox3.Text;
cc.salary = textBox4.Text;
cc.no = textBox5.Text;
c.Add(cc);
xs.Serialize(sw,cc);
this.Hide();
}
What should I do to serialize and deserialize all the objects created ?
class1 :
public class Class1
{
public String name;
public String age;
public String degree;
public String no;
public String salary;
}
deserialization code :
private void linkLabel1_LinkClicked_1(object sender, LinkLabelLinkClickedEventArgs e)
{
List<Class1> c2 = new List<Class1>();
XmlSerializer xml = new XmlSerializer(typeof(List<Class1>));
FileStream fs = new FileStream("Applicants.xml",FileMode.Open);
c2 = (List<Class1>)xml.Deserialize(fs);
label3.Text = ; //don't know what t write here
}

If you want to serialize the list, you have to create the Serializer for the type of List<Class1>.
XmlSerializer xs = new XmlSerializer(typeof(List<Class1>), new XmlRootAttribute("Applist"));
And then serialize the actual list instead of cc.
xs.Serialize(sw,c);

Related

static LIST of class returning same value

I have two classes, one contains the value I want to maintain and it is declared as [serializable] since I may want to store the results in a file later.
namespace WindowsFormsApp1
{
[Serializable]
public class Class1
{
string Something = "";
public Class1(string something)
{
Something = something;
}
public Class1()
{
Something = "";
}
public string something
{
get { return Something; }
set { Something = value; }
}
}
}
The second declares a List of this class along with a few access functions
namespace WindowsFormsApp1
{
class Class2
{
public static List<Class1> aClass = new List<Class1>();
public static int cnt = 0;
public void AddStaticString(Class1 aString)
{
aClass.Add(aString);
cnt++;
}
public string GetAllStrings()
{
string aFullString = "";
int cnt = 0;
while (cnt < aClass.Count)
{
aFullString = aClass[cnt].something;
cnt++;
}
return aFullString;
}
}
}
Now a simple bit of code to add to the LIST and try to extract it
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Class1 aClass = new Class1();
Class2 aSClass = new Class2();
aClass.something = "AAAAA";
aSClass.AddStaticString(aClass);
aClass.something = "BBBBB";
aSClass.AddStaticString(aClass);
aClass.something = "CCCCC";
aSClass.AddStaticString(aClass);
richTextBox1.Text = aSClass.GetAllStrings();
}
}
}
The richTextBox always displays the last item only (CCCCC), even though I can see the proper values being input into the LIST.
Can I not access the members of the LIST with aFullString = aClass[cnt].something; ?
You are just returning the last string from the list in GetAllStrings. Rather you could append it to existing item, or maybe separate them using comma, whatever you want.
For example, you can append those values using simply:
aFullString += aClass[cnt].something + ",";
But that would leave a comma at the end of the string.
Rather, if you need comma separated values, you could just join the strings using LINQ,
public string GetAllStrings()
{
return string.Join(",", aClass.Select(item => item.something));
}
Also, in button1_Click you are adding the same instance of Class1 to the list in Class2. If you need separate instances of the class, you should create new instance before calling AddStaticString:
private void button1_Click(object sender, EventArgs e)
{
Class2 aSClass = new Class2();
Class1 aClass = new Class1();
aClass.something = "AAAAA";
aSClass.AddStaticString(aClass);
aClass = new Class1();
aClass.something = "BBBBB";
aSClass.AddStaticString(aClass);
aClass = new Class1();
aClass.something = "CCCCC";
aSClass.AddStaticString(aClass);
richTextBox1.Text = aSClass.GetAllStrings();
}
You should, but the way you are assigning that aFullString variable will always show the last value of the list.
You should try it like this:
public string GetAllStrings()
{
string aFullString = "";
int cnt = 0;
while (cnt < aClass.Count)
{ //+ to keep the previous values too
aFullString += aClass[cnt].something;
cnt++;
}
return aFullString;
}
In this method:
public string GetAllStrings()
{
string aFullString = "";
int cnt = 0;
while (cnt < aClass.Count)
{
aFullString = aClass[cnt].something;
cnt++;
}
return aFullString;
}
You set aFullString to the last collection item's something.
What you want is probably string concatenation. You don't need while loop - for or foreach loop suit better, or even string.Join would be the best option:
public string GetAllStrings()
{
return String.Join(" ", aClass.Select(x => x.something);
}
Please, note that your code has many style and naming errors, unused or useless variables like class members Something and cnt, and doesn't make much sense in general.
You need to follow C# naming conventions and rules to make your code readable and understandable by other developers.

C# WPF Anonymous Pipes AnonymousPipeClientStream pipe direction out doesn't work

I'm developing a test application to communicate between 2 processes using Anonymous Pipes. I can send a message to the ClientView from the ServerView but I can't do the other way round since the pipe connection throws exceptions.
ServerCode
public class PipeServerHandler
{
private static AnonymousPipeServerStream serverSenderStream;
private static AnonymousPipeServerStream serverReceiverStream;
private static StreamWriter sw;
private static StreamReader sr;
public void ServerStart()
{
serverSenderStream = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable);
serverReceiverStream = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable);
string senderID = serverSenderStream.GetClientHandleAsString();
string receiverID = serverReceiverStream.GetClientHandleAsString();
ProcessStartInfo process = new ProcessStartInfo(#"C:\Users\VinushaP\Documents\Visual Studio 2015\Projects\CommunicationProject\ClientView\bin\Debug\ClientView.exe", senderID + "_" + receiverID);
process.UseShellExecute = false;
Process clientProcess = Process.Start(process);
serverSenderStream.DisposeLocalCopyOfClientHandle();
sr = new StreamReader(serverReceiverStream);
}
public string ReadData()
{
string temp;
temp = sr.ReadLine();
return temp;
}
}
Client Code
public class PipeClientHandler
{
private static AnonymousPipeClientStream clientReceiverStream;
private static AnonymousPipeClientStream clientSenderStream;
private static StreamReader sr;
private static StreamWriter sw;
public void ClientStart(string[] args)
{
string[] id = args[0].Split('_');
string senderID = id[0];
string receiverID = id[1];
clientReceiverStream = new AnonymousPipeClientStream(PipeDirection.In, senderID);
clientSenderStream = new AnonymousPipeClientStream(PipeDirection.Out, receiverID);
sw = new StreamWriter(clientSenderStream);
sw.AutoFlush = true;
}
public void WriteStream(string data)
{
sw.WriteLine(data);
clientSenderStream.WaitForPipeDrain();
}
}
This is the app.xaml.cs class which captures the Command Line args
private void Application_Startup(object sender, StartupEventArgs e)
{
PipeClientHandler handler = new PipeClientHandler();
if (e.Args.Length > 0)
{
handler.ClientStart(e.Args);
}
}
When sending data from PipeServerHandler to PipeClienHandler it works well, but when I send data from PipeClientHandler to PipeServerHandler it doesn't show me any messages.
clientSenderStream error
Anonymous pipes are one way. You'll need two anonymous pipes to do 2 way communications.

XmlSerializer.Serialize() fails to update XML file

So far I've followed the textbook route of adding adding data to an XML file; first, I created a class:
[Serializable]
public class Note
{
public string Notes { get; set; }
}
And then done this:
private void addButton_Click(object sender, RoutedEventArgs e)
{
string stringToAdd = textBox.Text;
Notes.Add(stringToAdd);
using (StringWriter myStringWirter = new StringWriter())
{
XmlSerializer myXML = new XmlSerializer(typeof(Note));
Note myNote = new Note();
myNote.Notes = stringToAdd;
myXML.Serialize(myStringWirter, myNote);
using (StreamWriter myStreamWriter = new StreamWriter("Notes.xml"))
{
myStreamWriter.Write(myStringWirter);
}
}
But Notes.xml doesn't get updated. Why?
Edit. Now it works. Just by using List instead of Note.

OpenFileDialog filename serialization

In writing a program where I need to serialize an AppSettings object which consists of several properties including one that will be used to store a last used filename, I have found that the FileName property is placed into my object (by assignment) but it does not serialize to the xml file. No exceptions are thrown and no data is written.
But conversely, if I programmtically modify the object
tc.TheDataFile = "c:\\Documents And Settings\\SomeUser\\Sample\\a test file.txt";
instead of
tc.TheDataFile = theDialog.FileName;
That will work. Can someone please provide some insight with regard to what I am missing?
Here is a simple version of the program that is directly related to the problem.
The test class which will theoretically hold the AppSettings ---
[Serializable()]
public class TestClass
{
private string m_TheDataFile;
private bool m_UseLastKnownDataFile = true;
public bool UseLastKnownDataFile
{
get
{
return m_UseLastKnownDataFile;
}
set
{
m_UseLastKnownDataFile = value;
}
}
public string TheDataFile
{
get
{
return m_TheDataFile;
}
set
{
m_TheDataFile = value;
}
}
}
public class TestClassHelper
{
public static TestClass Load()
{
XmlSerializer serializer = new XmlSerializer(typeof(TestClass));
TestClass retVal;
TextReader reader = null;
bool fileNotFound = false; ;
try
{
reader = new StreamReader("TestClassConfig.xml");
}
catch (FileNotFoundException)
{
fileNotFound = true;
}
if (fileNotFound)
{
retVal = new TestClass();
}
else
{
retVal = (TestClass)serializer.Deserialize(reader);
reader.Close();
}
return retVal;
}
public static void Save(TestClass settings)
{
XmlSerializer serializer = new XmlSerializer(typeof(TestClass));
TextWriter writer = new StreamWriter("TestClassConfig.xml");
serializer.Serialize(writer, settings);
writer.Close();
}
}
And here is the form which will prompt the user for a filename. In this test, there is a form with one button.
public partial class Form1 : Form
{
TestClass tc = null;
public Form1()
{
InitializeComponent();
tc = TestClassHelper.Load();
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog theDialog = new OpenFileDialog();
string fileName = string.Empty;
theDialog.CheckFileExists = true;
theDialog.CheckPathExists = true;
theDialog.Multiselect = false;
theDialog.FileName = string.Empty;
if (theDialog.ShowDialog() == DialogResult.OK)
{
tc.TheDataFile = theDialog.FileName;
}
else
{
tc.TheDataFile = string.Empty;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
TestClassHelper.Save(tc);
}
}
Edit To Add:
I'm using Microsoft Visual Studio 2005 Team Edition w/Dot Net 2.0.50727 SP1, with no options to upgrade the development environment.
Solution
I'm not exactly sure why this happens, but the OpenFileDialog control must change the current operating directory of the program. When the object is deserialized to the xml file, it no longer writes where it originally opened. Rather it is created in the new directory.
I corrected the problem by making the XML read and write location more specific.
The problem is that you are setting tc.TheDataFile = fileName; after the if block, but you never assign anything to fileName except when you initialize it to string.Empty. One fix would be:
if (theDialog.ShowDialog() == DialogResult.OK)
{
fileName = theDialog.FileName;
}
// record last used data file
tc.TheDataFile = fileName;
or just
if (theDialog.ShowDialog() == DialogResult.OK)
{
tc.TheDataFile = theDialog.FileName;
}
Note that running your test in the debugger and "watch"ing the variables would have made the problem fairly easy to spot.

Why cant I create a generic list of my class type?

public partial class About : System.Web.UI.Page
{
public class Class2
{
public int i = 1;
public string str = "Chandan";
}
protected void Page_Load(object sender, EventArgs e)
{
List<Class2> Object2 = new List<Class2>();
}
}
You are creating a collection of your objects.
In order to access the public fields of each object, you need to access each object in the list.
Did you mean?
Class2 Object2 = new Class2();
List<Class2> Object2 = new List<Class2>();
Object2.Add(new Class2());
Console.WriteLine(Object2[0].str);
I see no reason why Object2[0] shouldn't have accessible fields. And I just tested in LinqPad, and it worked correctly.
Or alternatively without a List:
Class2 Object2 = new Class2();
Console.WriteLine(Object2.str);
It's usually bad style to use public fields, but apart from that your code is ok and works.
List<Class2> Object2 = new List<Class2>(new[]{ new Class2(); });
Console.Out("{0}. {1}", Object2[0].i, Object2[0].str);
Should work fine.
Output of the following code
List count = 1
public partial class About : System.Web.UI.Page
{
public class Class2
{
public int i = 1;
public string str = "Chandan";
public string Data()
{
return i.ToString() + " " + str.ToString();
}
}
protected void Page_Load(object sender, EventArgs e)
{
Class2 Object1 = new Class2();
List<Class2> Object2 = new List<Class2>();
Object2.Add(Object1);
Response.Write("List count = " + Object2.Count.ToString());
}
}
You are right Matt. Thanks for the explanation. You Rock!!!

Categories

Resources