Serialization with c# code error - c#

I'm trying to generalize the serialization for one of my projects.
I have three main classes as follows:
test.cs - a simple test object
[Serializable()]
public class test : Attribute {
public string name = "";
public int ID = 0;
public test(string inputName, int inputID) {
name = inputName;
ID = inputID;
}
public test() {}
}
Serialization.cs - my main serialization class
public static void SerializeCollection<T>(string path, List<T> collection, Type type) {
System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(type);
System.IO.StreamWriter file = new System.IO.StreamWriter(path);
writer.Serialize(file, collection);
}
and finally Form1.cs - my form class
private void btnSerialize_Click(object sender, EventArgs e)
{
List<test> test = new List<test>();
test.Add(new test("testing1", 2));
Serialization.SerializeCollection("Test.txt", test, typeof(test));
}
When run and click the button I get this error:
'An unhandled exception of type 'System.InvalidOperationException' occurred in System.Xml.dll
Additional information: There was an error generating the XML document.'

You use incorrect type for serialization, you have change typeof(test) to typeof(List)
private static void SerializationTest()
{
List<test> test = new List<test>();
test.Add(new test("testing1", 2));
SerializeCollection("Test.txt", test, typeof(List<test>));
}
And to be honest, I would avoid type as a parameter for your method in your case:
private static void SerializationTest()
{
const string fileName = "Test.txt";
var tests = new List<test> {new test("testing1", 2)};
SerializeCollection(fileName, tests);
}
public static void SerializeCollection<T>(string fullFileName, IEnumerable<T> items)
{
var writer = new XmlSerializer(items.GetType());
var file = new StreamWriter(fullFileName);
writer.Serialize(file, items);
}

Related

Cannot implicitly convert type to GraphicalApplication.Shapes to String

I'm creating a unit test for one of the method of factory design pattern and when I create that class's object and try to call its method via that object then it says the above error.
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestCircle()
{
//arrange
String cmd = "circle 3";
String exp_val = "new Circle";
String actual_val = null;
//act
ShapeFactory factory_obj = new ShapeFactory();
String[] cmd_values = cmd.ToLower().Split(' ');
String code = cmd_values[0].Trim().ToLower();
actual_val = factory_obj.getShape(code);
//assert
Assert.AreEqual(exp_val, actual_val);
}
}

How to map any csv file to object with 1 method

I'm trying to map CSV file into class object with C#. My problem is that i have 3 different files, but I want to fallow DRY principles. Can someone tell me how to change 'ParseLine' method to make it possible?
C# consol app.
This is how my FileReader looks like:
public class FileReader<T> : IFileReader<T> where T : Entity
{
private readonly ITransactionReader<T> _transactionReader;
public FileReader(ITransactionReader<T> transactionReader)
{
_transactionReader = transactionReader;
}
public List<T> GetInfoFromFile(string filePath)
{
var lines = File.ReadAllLines(filePath);
var genericLines = new List<T>();
foreach (var line in lines)
{
genericLines.Add(_transactionReader.ParseLine(line));
}
return genericLines;
}
}
public interface IFileReader<T> where T : Entity
{
List<T> GetInfoFromFile(string filePath);
}
This is how the object should look like.
public class TransactionReader : ITransactionReader<Transaction>
{
public Transaction ParseLine(string line)
{
var fields = line.Split(";");
var transaction = new Transaction()
{
Id = fields[0],
Month = int.Parse(fields[1]),
Day = int.Parse(fields[2]),
Year = int.Parse(fields[3]),
IncomeSpecification = fields[4],
TransactionAmount = int.Parse(fields[5])
};
return transaction;
}
}
public interface ITransactionReader<T>
{
T ParseLine(string line);
}
This is how I run it for test purposes.
class Program
{
private static readonly string filePath = "C:/Users/<my_name>/Desktop/C# Practice/ERP/ERP/CsvFiles/Transaction.csv";
static void Main(string[] args)
{
ITransactionReader<Transaction> transactionReader = new TransactionReader();
IFileReader<Transaction> fileReader = new FileReader<Transaction>(transactionReader);
List<Transaction> Test()
{
var obj = fileReader.GetInfoFromFile(filePath);
return obj;
}
var list = Test();
}
}
I'm looking to modify that line:
genericLines.Add(_transactionReader.ParseLine(line));
and method arguments to make it open for any CSV fil.
I don't mind to change that composition into something more effective.

C# Serialize nested lists as XML

I want to serialize a class to XML that has a field of type List{List{String}} or String[][] or List{String[]}. My class was serializing and deserializing fine before I added the nested collection field, but it is throwing an InvalidOperationException when serializing or deserializing now.
I don't really care if I have to use arrays or lists for this specific instance, but it would be nice to know a general solution that can be used for any nested collection situation.
Currently my field is declared like this:
[XmlElement("foo")]
public List<String[]> foo;
This has worked fine for me on single level lists and arrays in the past.
Here is the full class:
[XmlRoot("ColumnUpdaterPrefs")]
public class ColumnUpdaterPrefs : Prefs {
public ColumnUpdaterPrefs() : base() {
defaultHeaders = new List<String[]>();
}
[XmlAttribute("autoFill")]
public Boolean autoFill = true;
[XmlAttribute("allowErrors")]
public Boolean allowErrors;
[XmlAttribute("allowZeroes")]
public Boolean allowZeroes;
[XmlElement("defaultHeaders")]
public List<String[]> defaultHeaders;
[XmlElement("defaultKey")]
public String defaultKey;
public override Object Clone() {
return new ColumnUpdaterPrefs() {
autoFill = this.autoFill,
allowErrors = this.allowErrors,
allowZeroes = this.allowZeroes,
defaultHeaders = this.defaultHeaders,
defaultKey = this.defaultKey
};
}
}
And its base class:
[Serializable]
public abstract class Prefs : ICloneable {
[XmlAttribute("name")]
public String name;
public Prefs(String name = null) {
this.name = name;
}
public String Serialize() {
var xs = new XmlSerializer(this.GetType()); //InvalidOperationException occurs here
using (var sw = new StringWriter()) {
xs.Serialize(sw, this);
var result = sw.ToString();
return result;
}
}
public static TPrefs Deserialize<TPrefs>(String xml)
where TPrefs : Prefs {
var xs = new XmlSerializer(typeof(TPrefs)); //InvalidOperationException occurs here
using (var sr = new StringReader(xml)) {
var result = (TPrefs)(xs.Deserialize(sr));
return result;
}
}
public void Write(ApplicationSettingsBase settings, Boolean save = false, String name = null) {
if (settings == null) throw new ArgumentNullException("settings");
if (name == null) name = this.name;
settings[name] = Serialize();
if (save) settings.Save();
}
public static TPrefs Read<TPrefs>(ApplicationSettingsBase settings, String name)
where TPrefs : Prefs {
if (settings == null) throw new ArgumentNullException("settings");
return Deserialize<TPrefs>((String)settings[name]);
}
public static TPrefs ReadOrDefault<TPrefs>(ApplicationSettingsBase settings, String name)
where TPrefs : Prefs, new() {
try { return Read<TPrefs>(settings, name); }
catch { return new TPrefs() { name = name }; }
}
public abstract Object Clone();
}
Here are the exception details:
A first chance exception of type 'System.InvalidOperationException' occurred in System.Xml.dll
Additional information: Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'System.Collections.Generic.List' to 'string[]'
error CS0029: Cannot implicitly convert type 'string[]' to 'System.Collections.Generic.List'
Is there a simple way to do this without creating a custom collection class?
thanks for the downvote, but it turns out the issue was just a matter of using the wrong attributes; something which could've been suggested based on my original code sample.
[XmlArray("outerList")]
[XmlArrayItem("innerList", typeof(List<String>))]
public List<List<String>> foo;

how do I link the class with main method in the same file

This is my first time using C# to create the program. How do I GetXMLData then add the record after that update the data in xml file? This program do not return me the error, but I could not see the data id "4" has been added into the record.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
namespace LinQ
{
class Program
{
private string path = "TestData.xml";
private void GetXMLData()
{
XDocument testXML = XDocument.Load(path);
var students = from student in testXML.Descendants("Student")
select new
{
ID = Convert.ToInt32(student.Attribute("ID").Value),
Name = student.Element("Name").Value
};
foreach (var student in students)
{
// Do other operations with each student object
}
}
private void InsertXMLData(string name)
{
XDocument testXML = XDocument.Load(path);
XElement newStudent = new XElement("Student",
new XElement("Name", name)
);
var lastStudent = testXML.Descendants("Student").Last();
int newID = Convert.ToInt32(lastStudent.Attribute("ID").Value);
newStudent.SetAttributeValue("ID", 4);
testXML.Element("Students").Add(newStudent);
testXML.Save(path);
}
private void UpdateXMLData(string name, int id)
{
XDocument testXML = XDocument.Load(path);
XElement cStudent = testXML.Descendants("Student").Where(c => c.Attribute("ID").Value.Equals(id.ToString())).FirstOrDefault();
cStudent.Element("Name").Value = name;
testXML.Save(path);
}
static void Main(string[] args)
{
//GetXMLData();
//InsertXMLData(string name);
}
}
}
Your Main function isn't doing anything.
change
static void Main(string[] args)
{
//GetXMLData();
//InsertXMLData(string name);
}
to
static void Main(string[] args)
{
GetXMLData();
InsertXMLData("paul");
}
you also have to make your methods static.
change
private void GetXMLData()
private void InsertXMLData(string name)
private void UpdateXMLData(string name, int id)
to
private static void GetXMLData()
private static void InsertXMLData(string name)
private static void UpdateXMLData(string name, int id)
If you want to access your methods without making them static, you have to create an instance of your object.
Like:
Program myProgram = new Program();
myProgram.GetXMLData();
myProgram.InsertXMLData("paul");
Please give proper path for xml file or keep it in exe location.
Below are the changes required to compile your code
class Program
{
private static string path = "D:\\TestData.xml";
static void Main(string[] args)
{
GetXMLData();
InsertXMLData("XYZ");
}
private static void GetXMLData()
{
// try
// {
XDocument testXML = XDocument.Load(path);
var students = from student in testXML.Descendants("Student")
select new
{
ID = Convert.ToInt32(student.Attribute("ID").Value),
Name = student.Element("Name").Value
};
foreach (var student in students)
{
// Do other operations with each student object
}
// }
//catch (Exception err)
//{
// MessageBox.Show(err.Message);
//}
}
private static void InsertXMLData(string name)
{
//try
//{
XDocument testXML = XDocument.Load(path);
XElement newStudent = new XElement("Student",
new XElement("Name", name)
);
var lastStudent = testXML.Descendants("Student").Last();
int newID = Convert.ToInt32(lastStudent.Attribute("ID").Value);
newStudent.SetAttributeValue("ID", 4);
testXML.Element("Students").Add(newStudent);
testXML.Save(path);
//}
//catch (Exception err)
//{
// MessageBox.Show(err.Message);
//}
}
private static void UpdateXMLData(string name, int id)
{
//try
//{
XDocument testXML = XDocument.Load(path);
XElement cStudent = testXML.Descendants("Student").Where(c => c.Attribute("ID").Value.Equals(id.ToString())).FirstOrDefault();
cStudent.Element("Name").Value = name;
testXML.Save(path);
//}
//catch (Exception err)
//{
// MessageBox.Show(err.Message);
//}
}
}
Having a quick look over the code, it appears there are two problems that could cause the application to perform incorrectly.
Firstly,
The method calls in Main() have been commented out, uncomment (remove the leading //) for the two methods.
Secondly,
The functions GetXMLData(), InsertXMLData(), and UpdateXMLData() are not static, and require a class instance to be used. You can fix this by adding the keyword static or use a class instance to call the functions.
Either change the function definitions to something like
private static void GetXMLData()
private static void InsertXMLData()
private static void UpdateXMLData()
or use a class instance
Program p = new Program();
p.GetXMLData();
There are no doubt other issues within the code, but this should get you started.

Unit testing a method which relies on multiple methods

I have a MethodA which calls MethodB in a separate class (one which follows an interface).
MethodB had a StreamReader in it, so I refactored the call to new StreamReader() into a new MethodC (in the same class as MethodB).
In order to test MethodA, i need to mock MethodB, but I also need to be able to test MethodB by mocking MethodC.
(I guess it's become clear I'm a little lost.)
namespace JimBob.CsvImporter.Entity
{
public interface IIOManager
{
TextReader ReturnReader(string path);
int GetNumberOfColumnsInFile(string filePath, List<string> errorMessageList);
}
public class IOManager : IIOManager
{
//MethodC
public TextReader ReturnReader(string filePath)
{
return new StreamReader(filePath);
}
//MethodB
public int GetNumberOfColumnsInFile(string filePath, List<String> errorMessageList)
{
int numberOfColumns = 0;
string lineElements = null;
try
{
using (StreamReader columnReader = (StreamReader)ReturnReader(filePath))
{
lineElements = columnReader.ReadLine();
string[] columns = lineElements.Split(',');
numberOfColumns = columns.Length;
}
return numberOfColumns;
}
catch (Exception ex)
{
errorMessageList.Add(ex.Message);
return -1;
}
}
}
public class EntityVerification
{
private IIOManager _iomgr;
public EntityVerification(IIOManager ioManager)
{
this._iomgr = ioManager;
}
//MethodA
public void ValidateNumberOfColumns(
string filePath, int userSpecifiedColumnCount,
List<String> errorMessageList
)
{
int numberOfColumnsInFile =
_iomgr.GetNumberOfColumnsInFile(filePath, errorMessageList);
if (userSpecifiedColumnCount != numberOfColumnsInFile) errorMessageList.Add(
"Number of columns specified does not match number present in file.");
}
At present my test is as follows:
[Test]
public void GetNumberOfColumnsInFile_ReturnsNumberOfColumns_Returns6()
{
Mock<IIOManager> mock = new Mock<IIOManager>();
mock.Setup(x => x.ReturnReader(It.IsAny<string>())).Returns(
new StringReader("the,big,fat,dog,ate,cats"));
EntityVerification testObject = new EntityVerification(mock.Object);
List<String> errorMessageList = new List<string>();
int i = testObject.GetNumberOfColumnsInFile("blabla.txt", errorMessageList);
Assert.AreEqual(i , 6);
}
But this was for when it was part of the Entity Verification Class.
Am i missing something? Any assistance would be appreciated!
In the test for MethodA, Mock MethodB. In a separate test, Mock MethodC to test MethodB.
The test for MethodA is independent from the test for MethodB, so don't over think this too much.

Categories