c# custom serialization and deserialize simple class - c#

i have this class
class MyClass{
int x;
byte[] arr;
}
I want to serialize it to text file but on custom way.
I want before I write the x value i want to write : the x value is: x.
and to do some manipulate on the arr (like +1 on every value) and move tab.
and then " the value again is" the value of X "have a nice day" with tab
how can i serialize like this to txt file,
and how can i deserialize from txt file like that to MyClass?
for example: x=4, arr={1,2,3}
the txt file will be
the value of X is: 4
arr is: 2,3,4
the value again is:5 have a nice day
how can i do this please?
i don't want to do special Get property for that var , because on my program i use this Get .

Serializing is different than what you are trying to do, but if you want special formatted output, some would do an override of the ToString() method, but you can just create another method something like...
public string textOutput()
{
var sb = new StringBuilder();
sb.AppendFormat("the value of X is: {0}\r\n arr is: ", x);
for (var i = 0; i < arr.Length; i++)
sb.AppendFormat("{0}{1}", i == 0 ? "" : ", ", arr[i]);
// don't know where your 5 value is coming from though... but place-holdered it
sb.AppendFormat("\r\n the value again is: {0} have a nice day", 5);
return sb.ToString();
}
and write your output as needed. Or you could create this as its own getter property and that too.

Related

How do you return an array in a procedure back to the main procedure in C#?

static string readfileName(string[] name)
{
using (StreamReader file = new StreamReader("StudentMarks.txt"))
{
int counter = 0;
string ln;
while ((ln = file.ReadLine()) != null)
{
if (ln.Length > 4)
{
name[counter] = ln;
counter++;
}
}
file.Close();
return name;
}
}
This is the procedure I'm currently trying to return the array name[50] but the compile time error I can't fix states
"Error CS0029 Cannot implicitly convert type 'string[]' to 'string' "
You don't need to. Your main method passed the array to this method, this method filled it. It doesn't need to hand it back because the object pointed to by your 'name` variable is the same object as pointed to by the original variable in the main method; your main method already has all the array data:
static void Main(){
var x = new string[10];
MyMethod(x);
Console.Write(x[0]); //prints "Hello"
}
static void MyMethod(string[] y){
y[0] = "Hello";
}
In this demo code above we start out with an array of size 10 that is referred to by a variable x. In memory it looks like:
x --refers to--> arraydata
When you call MyMethod and pass x in, c# will create another reference y that points to the same data:
x --refers to--> arraydata <--refers to-- y
Now because both references point to the same area of memory anything that you do with y, will also affect what x sees. You put a string (like I did with Hello) in slot 0, both x and y see it. When MyMethod finishes, the reference y is thrown away, but x survives and sees all the changes you made when working with y
The only thing you can't do is point y itself to another different array object somewhere else in memory. That won't change x. You can't do this:
static void MyMethod(string[] y){
y = new string[20];
}
If you do this your useful reference of x and y pointing to the same area of memory:
x ---> array10 <--- y
Will change to:
x ---> array10 y ---> array20
And then the whole array20 and the y reference will be thrown away when MyMethod finishes.
The same rule applies if you call a method that supplies you an array:
static void MyMethod(string[] y){
y = File.ReadAllLines("some path"); //this also points y away to a new array made by ReadAllLines
}
It doesn't matter how or who makes the new array. Just remember that you can fiddle with the contents of an object pointed to by y all you like and the changes will be seen by x, but you can't change out the entire object pointed to by y and hope x will see it
in that case you WOULD have to pass it back when you're done:
static string[] MyMethod(string[] y){
y = new ...
return y;
}
And the main method would have to capture the change:
Main(...){
string[] x = new string[10];
string[] result = MyMethod(x);
}
Now, while I'm giving this mini lesson of "pass by reference" and "pass by value" (which should have been called "pass by original reference" and "pass by copy of reference") it would be useful to note that there is a way to change things so MyMethod can swap y out for a whole new object and x will see the change too.
We don't really use it, ever; there is rarely any need to. Just about the only time it's used is in things like int.Parse. I'm telling you for completeness if education so that if you encounter it you understand it but you should always prefer a "change the contents but not the whole object" or a "if you make a new object pass it back" approach
By marking the y argument with the ref keyword, c# wont make a copy of the reference when calling the method, it will use the original reference and temporarily allow you to call it y:
static void MyMethod(ref string[] y){
y = new array[20];
}
Our diagram:
x ---> array10data
Temporarily becomes:
x a.k.a y ---> array10data
So if you point y to a new array, x experiences the change too, because they're the same reference; y is no longer a different reference to the same data
x a.k.a y ---> array20data
Like I say, don't use it- we always seek to avoid it for various reasons.
Now, I said at the start "you don't need to" - by that, and for the reasons above, I meant you don't need to return anything from this method
Your method receives the array it shall fill (from the file) as a parameter; it doesn't make a new array anywhere so there isn't any need to return the array when done. It will just put any line longer than 4 chars into an array slot. It could then finish without returning anything and the method that called this method will see the changes it made in the array. This is just like my code, where MyMethod changes slot 0 of the array, MyMethod was declared as void so it didn't need to make a return statement , and my Main method god could still see the Hello that I put in the array. In the same vein, your Main method will see all those lines from the file if you make your ReadFileName method (which should perhaps be called FillArray) because it fills the array called name
The most useful thing your method could return is actually an integer saying how many lines were read; the array passed in is of a fixed size. You can't resize it because that entails making a new array which won't work for all those reasons I talked about above. If you were to make a new array and return it there wouldn't be any point in passing an array in.
There are thus several ways we could improve this code but to my mind they come down to two:
don't pass an array in; let this method make a new array and return it. The new array passed back can be exactly sized to fit
keep with the "pass an array in" idea and return an integer of how many lines were actually read instead
For the second idea (which is the simplest to implement) you have to change the return type to int:
static int ReadFileName(string[] name)
And you have to return that variable you use to track which slot to put the next thing in, counter. Counter is always 1 greater than the number of things you've stored so:
return counter - 1;
Your calling method can now look like:
string[] fileData = new string[10000]; //needs to be big enough to hold the whole file!
int numberOfLinesRead = ReadFileName(fileData);
Can you see now why ReadFileName is a bad name for the method? Calling it FillArrayFromFile would be better. This last line of code doesn't read like a book, it doesn't make sense from a natural language perspective. Why would something that looks like it reads a file name (if that even makes sense) take an array and return an int - calling it ReadFileName makes it sound more like it searches an array for a filename and returns the slot number it was found in. Here ends the "name your methods appropriately 101"
So the other idea was to have the Read method make its own array and return it. While we are at it, let's call it ReadFileNamed, and have it take a file path in so it's not hard coded to reading just that one file. And we will have it return an array
static string[] ReadFileNamed(string filepath)
^^^^^^^^ ^^^^^^^^^^^^^^^
the return type the argument passed in
Make it so the first thing it does is declare an array big enough to hold the file (there are still problems with this idea, but this is programming 101; I'll let them go. Can't fix everything using stuff you haven't been taught yet)
Put this somewhere sensible:
string lines = new string[10000];
And change all your occurrences of "name" to be "lines" instead - again we name our variables we'll just like we name our methods sensibly
Change the line that reads the fixed filename to use the variable name we pass in..
using (StreamReader file = new StreamReader(filepath))
At the end of the method, the only thing left to do is size the array accurately before we return it. For a 49 line file, counter will be 50 so let's make an array that is 49 big and then fill it using a loop (I doubt you've been shown Array.Copy)
string[] toReturn = new string[counter-1];
for(int x = 0; x < toReturn.Length; x++)
toReturn[x] = lines[x];
return toReturn;
And now call it like this:
string[] fileLines = ReadFileNamed("student marks.txt");
If you're looking to return name[50] and you know that will be populated, why not go with:
static string readfileName(string[] name)
{
using (StreamReader file = new StreamReader("StudentMarks.txt"))
{
int counter = 0;
string ln;
while ((ln = file.ReadLine()) != null)
{
if (ln.Length > 4)
{
name[counter] = ln;
counter++;
}
}
file.Close();
return name[50];
}
}
You're getting the error because your method signature indicates that you're going to return a string, but you're defining name as a string[] in the argument. If you simply select a single index of your array in the return statement, you'll only return a string.
You have defined your method to return a string, yet the code inside is returning name, which is a string[]. If you want it to return a string[], then change the signature to specify that:
static string[] ReadFileName(string[] name)
However, since your method is only populating the array that was passed in, it's not really necessary to return the array, since the caller already has a reference to the array we're modifying (they passed it to our method in the first place).
There is a potential problem here, though
We're expecting the caller to pass us an array of the appropriate length to hold all the valid lines from the file, yet that number is unknown until we read the file. We could return an array of the size they specified with either empty indexes at the end if it was too big, or incomplete data if it was too small, but instead we should probably just return them a new array, and not require them to pass one to us.
Note that it's easier to use a List<string> instead of a string[], since lists don't require any knowledge of their size at instantiation (they can grow dynamically). Also, we no longer need a counter variable (since we're using the Add method of the list to add new items), and we can remove the file.Close() call since the using block will call that automatically (one of the cool things about them):
static string[] ReadFileName()
{
List<string> validLines = new List<string>();
using (StreamReader file = new StreamReader("StudentMarks.txt"))
{
string ln;
while ((ln = file.ReadLine()) != null)
{
if (ln.Length > 4)
{
validLines.Add(ln);
}
}
}
return validLines.ToArray();
}
And we can simplify the code even more if we use some static methods of the System.IO.File class:
static string[] ReadFileName()
{
return File.ReadLines("StudentMarks.txt").Where(line => line.Length > 4).ToArray();
}
We could also make the method a little more robust by allowing the caller to specify the file name as well as the minimum line length requirement:
static string[] ReadFileName(string fileName, int minLineLength)
{
return File.ReadLines(fileName)
.Where(line => line.Length >= minLineLength).ToArray();
}
Well, you are trying to do several thing in one method:
Read "StudentMarks.txt" file
Put top lines into name existing array (what if you have too few lines in the file?)
return 50th (magic number!) item
If you insist on such implementation:
using System.Linq;
...
static string readfileName(string[] name)
{
var data = File
.ReadLines("StudentMarks.txt")
.Where(line => line.Length > 4)
.Take(name.Length);
int counter = 0;
foreach (item in data)
if (counter < name.Length)
name[counter++] = item;
return name.Length > 50 ? name[50] : "";
}
However, I suggest doing all things separately:
// Reading file lines, materialize them into string[] name
string[] name = File
.ReadLines("StudentMarks.txt")
.Where(line => line.Length > 4)
// .Take(51) // uncomment, if you want at most 51 items
.ToArray();
...
// 50th item of string[] name if any
string item50 = name.Length > 50 ? name[50] : "";
Edit: Splitting single record (name and score) into different collections (name[] and score[]?) often is a bad idea;
the criterium itself (line.Length > 4) is dubious as well (what if we have Lee - 3 letter name - with 187 score?).
Let's implement Finite State Machine with 2 states (when we read name or score) and read (name, score) pairs:
var data = File
.ReadLines("StudentMarks.txt")
.Select(line => line.Trim())
.Where(line => !string.IsNullOrEmpty(line));
List<(string name, int score)> namesAndScores = new List<(string name, int score)>();
string currentName = null;
foreach (string item in data) {
if (null == currentName)
currentName = item;
else {
namesAndScores.Add((currentName, int.Parse(item)));
currentName = null;
}
}
Now it's easy to deal with namesAndScores:
// 25th student and his/her score:
if (namesAndScores.Count > 25)
Console.Write($"{namesAndScores[25].name} achieve {namesAndScores[25].score}");

Parsing string as int with "Model.x" property in for loop remains in string format

I have a simple form that accepts a number from a radio button selection (1-5) of 11 questions and posts the values into a database as varchar(10) data. I intend to send the user to a result page that lists the sum of these scores through a simple for loop, but when I try parsing the data to integer format, it simply results in zero due to error parsing. Here's an example of my code:
// Q1 - Q11 are the questions in my Db, using Model property
int sum = 0;
int temp = 0;
String question;
for (int i = 11; i >= 1; i--)
{
question = "Model.Q" + i.ToString();
temp = int.Parse(question);
sum += temp;
}
return sum;
What's strange is that if I parse them individually, such as writing:
Int32.TryParse(Model.Q5, out temp);
I am able to parse the data just fine. My console shows that the loop keeps the question variable as "Model.Qx" with quotations, ultimately resulting in 0 for the sum. I have also tried using Int32.TryParse(); for that as well and it resulted in no difference, besides handling the error.
Can a string simply not be parsed if it contains punctuation in concatenation with the i variable, or am I missing something else here? I want to avoid parsing each question individually, as it looks rather ugly in code.
Thanks in advance.
You problem is that you're trying to access a variable by using a string with the same name. This won't work, in the same way that the name gitgecko is not you.
If your model has got a number of properties with similar names, you could write a function to switch between them:
object GetQ(int number)
{
switch(number)
{
case 1: return Model.Q1;
case 2: return Model.Q2;
// etc...
}
}
Or you could change your model to store these variables in an array or list, or whatever is appropriate.
For example, if you've currently got:
class Model
{
string Q1;
string Q2:
// repeated 11 times
You could have:
class Model
{
string[] Q = new string[11];
}
which gives you the ability to do Model.Q[x]

How to declare and use a list of string array?

I need to read a line in a file.
Based on the first 3 characters in the file, I can determine a type of record.
This indicates the number of strings the line needs to be split into.
I need to hold all lines of the same type in a List.
How do I do this?
My sample file would look like
123|gf|hf|gr|9
145*gf*43*434*9*645*554
123|grf|fe|yr|9
So all 123 would be in a list of string array type of length 4 like :
public List<string[]> NTE =new List<string[4]>();
Except declaring a length isn't being accepted by the compiler
You could use
List<string[]> NTE =new List<string[]>();
And then as you need to add an element to the NTE, you only need to specify that the size will be 4:
NTE.Add(new string[4]); //here it is defined having size of 4, not in the list declaration
Then when you use it:
NTE[0] = ...something
That is going to be a string[4] array
class ArrayofFour
{
string[] a = new string[4];
public string this[int i]
{
get
{
return a[i];
}
set
{
a[i] = value;
}
}
}
Use the ArrayofFour instead of an array, you can use it like an array using the indexers. This will take care of validation you need.
Then you can have a List<ArrayofFour> NTE = new List<ArrayofFour>();
I think this is what you need or at least help you get there.

Convert array element as concatenated string to double in C#

I'm (very) new to C#; I'm sure the solution here is simple but I can't figure it out.
Suppose I have a simple array of temperatures for Friday. I receive an abbreviation for the day and an hour (integer) from somewhere and I want to use it to print an element from the array:
using System;
public class Program
{
public static void Main()
{
double[] Friday = {54.5, 61.0, 63.5, 58.0};
string Today = "Fri";
int Hour = 1;
double parsed = Convert.ToDouble(Today + "day[" + int + "]");
Console.WriteLine(parsed);
}
}
Given these conditions, how do I output 61.0? Then end result should be equivalent to Console.WriteLine(Friday[1]);
If I really wanted to achieve that I would use a dictionary:
Dictionary<string, double[]> dayToValues =
new Dictionary<string, double[]>
{
{"Monday", new double[] {1.0, 2.0, 3.0} },
{"Friday", new double[] {4.0, 5.0, 6.0} }
};
string today = "Fri";
int hour = 0;
double firstHourValue = dayToValues[today + "day"][hour];
Console.WriteLine(firstHourValue); // prints "4"
If you really need to dynamically build the name of a variable and access it, you have to use reflection. Something like:
string fieldName = today.ToLower() + "day";
double[] todays = GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this) as double[];
Console.WriteLine(todays[1]); // prints "8"
This assumes that your have a private field in the current class:
double[] friday = { 7.0, 8.0, 9.0 };
Of course the reflection code depends on the exact location and scope of the variables. And obvioulsy you would need some null reference checks to use it in the real world. Anyway, using reflection looks quite irrelevant for what seem to be your needs. Use it only if you really have to.
c# uses zero-relative indexing. This means that the 1st element in the array has an index of zero. So you most likely mean Friday[0].
c# also has the ToString method on all objects. This returns a "human readable" representation of the object. So you can do
Console.WriteLine(Friday[0].ToString());
Also, WriteLine will auto-magically convert any object passed to it into its string repsentation. So this will also work
Console.WriteLine(Friday[0]);
If you want text and a value, then use a Format string, as in
Console.WriteLine("Friday {0}", Friday[0]);
See https://msdn.microsoft.com/en-us/library/system.string.format%28v=vs.110%29.aspx for more details on format strings.

System.Int32[] displaying instead of Array elements [duplicate]

This question already has answers here:
How can I print the contents of an array horizontally?
(12 answers)
How does the .ToString() method work?
(4 answers)
Closed 9 years ago.
I am trying to display array elements but always getting this output System.Int32[]
instead of integer elements.
using System.IO;
using System;
class Test
{
public static void Main()
{
int[] arr=new int [26];
for(int i = 0; i < 26; i++)
arr[i] = i;
Console.WriteLine("Array line : "+arr);
}
}
You could use string.Join
Console.WriteLine("Array line : "+ string.Join(",", arr));
You need to loop over the content and print them -
Console.WriteLine("Array line: ");
for(int i=0;i<26;i++)
{
arr[i]=i;
Console.WriteLine(" " + arr[i]);
}
Simply printing arr will call ToString() on array and print its type.
Printing an array will call the ToString() method of an array and it will print the name of the class which is a default behaviour. To overcome this issue we normally overrides ToString function of the class.
As per the discussion here we can not override Array.ToString() instead List can be helpful.
Simple and direct solutions have already been suggested but I would like to make your life even more easier by embedding the functionality in Extension Methods (framework 3.5 or above) :
public static class MyExtension
{
public static string ArrayToString(this Array arr)
{
List<object> lst = new List<object>();
object[] obj = new object[arr.Length];
Array.Copy(arr, obj, arr.Length);
lst.AddRange(obj);
return string.Join(",", lst.ToArray());
}
}
Add the above code in your namespace and use it like this: (sample code)
float[] arr = new float[26];
for (int i = 0; i < 26; i++)
arr[i] = Convert.ToSingle(i + 0.5);
string str = arr.ArrayToString();
Debug.Print(str); // See output window
Hope you will find it very helpful.
NOTE: It should work for all the data types because of type object. I have tested on few of them
You are facing this problem because your line
Console.WriteLine("Array line : "+arr);
is actually printing the type of arr. If you want to print element values you should use the index number to print the value like
Console.WriteLine("Array line : "+arr[0]);

Categories