Move switch statement to text file - c#

Here is my situation every time we add a new product to our catalog we need to go through add the product to this snippet and recompile the dll's, then push them out to all of the servers.
What I'd like to be able to do is to be able to just add a line to a text file that the DLL then reads in. To make things easy the file will reside in the same folder as the DLL's. The main issue is there are several places that call this all of which pass in the productId, so changing that would not be feasible.
void AssignFunctions(int productId)
{
switch (productId)
{
case 31:
IsSpread = CalendarIsSpread;
IsLeftPage = CalendarIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
case 49:
case 63:
case 64:
case 69:
case 70:
...
case 592:
case 630:
case 686:
IsSpread = NeverASpread;
IsLeftPage = GeneralIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
case 73:
IsSpread = GeneralIsSpread;
IsLeftPage = GeneralIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
case 444:
case 445:
IsSpread = BookletIsSpread;
IsLeftPage = BookletLeftPage;
GetOppositePageNumber = BookletGetOppositePageNumber;
break;
default:
IsSpread = GeneralIsSpread;
IsLeftPage = GeneralIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
}
}
Another scenario would be to take the productId and compare it to the text file and then act accordingly. In that case the call would look something like this:
void AssignFunctions(int productId)
{
//Do Something here to get the productSpreadType
switch (productSpreadType)
{
case 1:
IsSpread = CalendarIsSpread;
IsLeftPage = CalendarIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
case 2:
IsSpread = NeverASpread;
IsLeftPage = GeneralIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
case 3:
IsSpread = GeneralIsSpread;
IsLeftPage = GeneralIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
case 4:
IsSpread = BookletIsSpread;
IsLeftPage = BookletLeftPage;
GetOppositePageNumber = BookletGetOppositePageNumber;
break;
default:
IsSpread = GeneralIsSpread;
IsLeftPage = GeneralIsLeftPage;
GetOppositePageNumber = GeneralGetOppositePageNumber;
break;
}
}
In this case the text file would look something like this:
31 1
49 2
63 2
...
73 3
444 4
If the productId is not listed it would just then perform the default action.
.NET is not my forte and it takes a good half day every time we add new products to remember how to update this. As I am the only one with Visual Studio running on Windows the task always fall to me. With the exception of having to make this change we don't have to touch the code base, so it would be nice to not have to build the DLL's every time and be able to pass the task of making sure this gets updated to one of our junior developers, who make are the ones responsible for adding new products.

C# is a static language and is not meant for dynamic code like you're suggesting.
I would however consider a different design where you can read different categories from a database and act on them as categories rather than individual items with the same handling.
Looks like you can group a lot of these together.
You can also consider a config file as the source for the categories.

You could use a little reflection magic:
using System;
using System.Linq;
using System.Reflection;
public class Program
{
public static void Main()
{
// Test Data
DoProduct(31);
DoProduct(63);
DoProduct(49);
DoProduct(49);
DoProduct(61);
}
public static void DoProduct(int productId)
{
string data = "";
bool methodExecuted = false;
// I am loading the string "data" with test data for simplicity.
// In real life, you'll load this from your file intead.
data = data + "31 MyFirstFunction" + Environment.NewLine;
data = data + "49 MySecondFunction" + Environment.NewLine;
data = data + "63 MyThirdFunction" + Environment.NewLine;
foreach (string str in data.Replace(Environment.NewLine, "\n").Replace('\r', '\n').Split('\n'))
{
if (string.IsNullOrEmpty(str))
continue;
int pid = int.Parse(str.Split(' ')[0]);
string func = str.Split(' ')[1];
if (pid != productId)
continue;
Type type = typeof(Program);
MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
MethodInfo method = methods.FirstOrDefault(z => z.Name.Equals(func));
if (method == null) {
continue;
}
method.Invoke(null, null);
methodExecuted = true;
}
if (!methodExecuted)
{
MyDefaultFunction();
}
}
public static void MyFirstFunction()
{
Console.WriteLine("This is MyFirstFunction()!");
}
public static void MySecondFunction()
{
Console.WriteLine("This is MySecondFunction()!");
}
public static void MyThirdFunction()
{
Console.WriteLine("This is MyThirdFunction()!");
}
public static void MyDefaultFunction()
{
Console.WriteLine("This is MyDefaultFunction()!");
}
}
This will allow you to create a text file, like this:
31 MyFunction
63 AnotherFunction
...
And using reflection, it will execute the correct function every time you pass in a product id. If the product id is not in the text file, it will call the default function.
Here is a fiddle of it in action: https://dotnetfiddle.net/7Atpq7

If you really must use a text file you could load it into a multiple value dictionary using a struct, then perform a search on that dictionary
assuming test data of the following in a text file called test.txt:
1,value1,value2
2,value1,value2
...
you could do something like this:
class Program
{
// declare test data
public static int[] _products = new int[] { 1, 2, 3, 4, 5 };
// Searchable value dictionary to be filled by file
static Dictionary<int,Values> d = new Dictionary<int,Values>();
static void Main(string[] args)
{
// Read the file line by line into the dictionary
string line;
System.IO.StreamReader file =
new System.IO.StreamReader("c:\\test\\test.txt");
while ((line = file.ReadLine()) != null)
{
string[] values = line.Split(',');
int productId = int.Parse(values[0]);
Values v = new Values();
v.Value1 = values[1];
v.Value2 = values[2];
d.Add(productId, v);
}
file.Close();
// check our loaded config file
foreach (int p in _products)
{
if (d.Keys.Contains(p))
{
// we've found a match in the file
// your logic goes here!
}
else
{
// no match was found
// handle missing data
}
}
}
// struct to hold your data from text file
struct Values
{
public string Value1;
public string Value2;
}
}

Related

solution needed with a homework c# (cs7036)

I am trying to make a menu with different options on replit where the user can choose an option.
I am making the options on seperate files, so I later can call for the methods from those files instead of writing everything in the main file.
One of these menuoptions will have an option with a random generator which will generate a random string.
I created the method on another file, But when it gave me an error (7036) when i tried to call it to the main method.
I have pasted an example of the code here below, But you can also access and run the code on this link: https://replit.com/#AY2002/testc22#main.cs Which will be easier to understand. I am a begginer and, Therefore seeking a simple answer.
Thank you!
//MAIN replit FILE
using System;
using System.Collections.Generic;
namespace Namespace1 {
// This is the main file where the menu is built. the menu is working fine.
// the menu have 4 options and an exit option, which will be divided into 4 different replit files and one of them will have a method that randomly generates a string. you can see the method when you scroll down near to the bottom of the main file.
class Program {
public static void Main (string[] args)
{
string[] Menuchoises = new string [] {"Choise1","Choise2","Choise3","Choise4","Choise5"};
int x = 0;
while (true){
Console.Clear();
Console.WriteLine("welcome to menu");
Console.WriteLine();
Console.CursorVisible = false;
if(x == 0) {
Console.WriteLine(" " + Menuchoises[0] + " {");
Console.WriteLine(Menuchoises[1]);
Console.WriteLine(Menuchoises[2]);
Console.WriteLine(Menuchoises[3]);
Console.WriteLine(Menuchoises[4]);
}
else if(x == 1) {
Console.WriteLine(Menuchoises[0]);
Console.WriteLine(" " + Menuchoises[1] + " {");
Console.WriteLine(Menuchoises[2]);
Console.WriteLine(Menuchoises[3]);
Console.WriteLine(Menuchoises[4]);
}
else if(x == 2) {
Console.WriteLine(Menuchoises[0]);
Console.WriteLine(Menuchoises[1]);
Console.WriteLine(" " + Menuchoises[2] + " {");
Console.WriteLine(Menuchoises[3]);
Console.WriteLine(Menuchoises[4]);
}
else if(x == 3) {
Console.WriteLine(Menuchoises[0]);
Console.WriteLine(Menuchoises[1]);
Console.WriteLine(Menuchoises[2]);
Console.WriteLine(" " + Menuchoises[3] + " {");
Console.WriteLine(Menuchoises[4]);
}
else if(x == 4) {
Console.WriteLine(Menuchoises[0]);
Console.WriteLine(Menuchoises[1]);
Console.WriteLine(Menuchoises[2]);
Console.WriteLine(Menuchoises[3]);
Console.WriteLine("\t" + Menuchoises[4] + " {");
}
var key = Console.ReadKey();
if (key.Key == ConsoleKey.DownArrow && x != Menuchoises.Length -1) {
x++;
}
else if (key.Key == ConsoleKey.UpArrow && x>=1) {
x--;
} else if (key.Key == ConsoleKey.Enter) {
switch (x) {
case 0:
Menuchoise1();
break;
case 1:
Menuchoise2();
break;
case 2:
Menuchoise3();
break;
case 3:
Menuchoise4();
break;
case 4:
Menuchoise5();
break;
}
}
}
}
public static void Menuchoise1() {
// Class2.second is the name of the second class which will be the method that will appear when you choose the 1st option in the menu.
// The second class is in the second file which you`ll see below the main file
// The CS 7036 error seems to be appearing here
Class2.second();
Console.Clear();
Console.ReadKey();
}
public static void Menuchoise2() {
Console.Clear();
Console.ReadKey();
}
public static void Menuchoise3() {
Console.Clear();
Console.ReadKey();
}
public static void Menuchoise4() {
Console.Clear();
Console.ReadKey();
}
public static void Menuchoise5() {
Console.Clear();
Console.WriteLine("press enter to exit the menu");
Console.ReadKey();
Console.Clear();
Environment.Exit(1);
}
}
}
// SECOND replit FILE
//this is the second file where i have the random value generator.
using System;
using System.Collections.Generic;
namespace Namespace1 {
// class name of the second file
public class Class2 {
// the string[]args function that will later be put in the main file in order to use this method in the menu
public static string second(string[] Random) {
string[] RandomChoises = new string [4];
// list on options which will be randomly generated
RandomChoises[0] = "C1";
RandomChoises[1] = "C2";
RandomChoises[2] = "C3";
RandomChoises[3] = "C4";
RandomChoises[4] = "C5";
for (int i = 0; i < RandomChoises.Length; i++)
{
Console.WriteLine(RandomChoises[i]);
}
// the choises are randomly generated here
Random rnd = new Random();
int Randomanswer = rnd.Next(1,RandomChoises.Length);
Console.WriteLine("You got the answer: " + RandomChoises[Randomanswer]);
return Convert.ToString(Randomanswer);
}
}
}
As mentioned in the comments, the problem is that the second method takes a parameter, but is not called with one. Since the parameter is not used it should be removed. Cleaning up the class a bit should give you something like:
public static class RandomHelpers{
public static string GetRandomValue() {
// use collection initializer
string[] choices= new []{"C1","C2","C3","C4","C5"}
// use foreach loop
foreach(var choice in choices){
Console.WriteLine(choice );
}
// You should probably not recreate the random object for each method call
// But this should work fine for demonstration purposes
Random rnd = new Random();
// start from zero
int randomIndex = rnd.Next(0,RandomChoises.Length);
var randomValue = choices[randomIndex];
// You should probably just return the random value,
// and let the caller print it to console.
Console.WriteLine("You got the answer: " + randomValue );
// Either return the index as an int, or the value as a string
// Do not convert numbers to strings unless you are writing to the console/file
return randomValue ;
}
}
This should work better. As you get more experience you should find better ways to split functionality into reusable methods.
You have an issue with the way you are defining the array in second.cs. You either need explicitly say how many elements your array will have, like this:
string[] RandomChoice = new string[5];
Or you can leave the number out and let the compiler infer it from the number of elements you put in the {}, like this:
string[] RandomChoises = new string[] { "C1", "C2", "C3", "C4", "C5" };
You can read more details about declaring arrays in C# here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/
After you fix that see JonasH answer about the method parameters in second().

How to check if an array contains sequential, evenly spaced numbers?

I'm creating a program to determine who wins a game of poker.
For context, the input data was in the format:
8C TS KC 9H 4S 7D 2S 5D 3S AC
Where the first character indicates the strength of the card (A = Ace, T = 10, J = Jack etc) and the second indicates the suit. The first 5 cards are player one and the last 5 are player two.
The data has been read into an array, split into two arrays containing each player's hands, playerOneHands and playerTwoHands. Then this array is further split into an array describing the strengths of the cards (converting the string into integers and turning "T" into int 10, "J" into int 11 etc), playerOneCardStrengths and playerTwoCardStrengths, as well as the suits, playerOneCardSuits and playerTwoCardSuits. The strengths array was then sorted in order from highest to lowest using
Array.Sort(playerOneCardStrengths, playerOneCardSuits);
I would now like to pass these values through a function which checks whether or not a royal flush has occured. It would input these two arrays and output a boolean describing whether a royal flush had occured.
A royal flush is defined in poker as a hand containing an Ace, King, Queen, Jack and Ten all of the same suit.
This is what I have so far:
static bool determineRoyalFlush(int[] cardStrengths, string[] cardSuits)
{
bool royalFlush = false;
if (cardSuits[0] != cardSuits[1])
{
return royalFlush = false;
}
else
{
if (cardStrengths[0] != 14)
{
return royalFlush = false;
}
else
{
if (cardStrengths[0] - cardStrengths[1] == 1
&& cardStrengths[1] - cardStrengths[2] == 1
&& cardStrengths[2] - cardStrengths[3] == 1
&& cardStrengths[3] - cardStrengths[4] == 1)
{
return royalFlush = true;
}
else
{
royalFlush = false;
}
}
}
}
My two questions:
Is there a neater way to check whether whether the cardStrengths array contains sequential numbers in a number line? the last bit of code above essentially checks whether cardStrengths[0] = 14 and [1] = 13 and [2] = 12 etc. But I would like to reuse this code to check for a regular flush, and I'm just curious about how I could check, say, an array a million integers long whether or not they all count up 1 2 3 4 .. etc, or count down again.
Secondly, and more importantly, I'm getting the error "Not all code paths return a value", but I can't see any scenario where this doesn't return true or false? I'm overlooking something somewhere.
Thanks!
To Solve Your Second Question :
Your last else statement (royalFlush = False ) does not return anything . Changing the code to return False should it .
You can use a for loop to compare the items to the previous ones by starting the loop with the second one (i.e. with index 1 instead of 0).
if (cardStrengths[0] != 14) {
return false;
}
for (int i = 1; i < cardStrengths.Length; i++) {
if (cardStrengths[i - 1] - cardStrengths[i] != 1) {
return false;
}
}
return true;
The variable royalFlush is not needed.
It would add much clarity if you structured the game by adding some types representing the concepts of the game
public enum Suit
{
Club,
Diamond,
Heart,
Spade
}
public enum Rank
{
Two = 2, Three = 3, Four = 4, Five = 5, Six = 6, Seven = 7, Eight = 8, Nine = 9, Ten = 10,
Jack = 11, Queen = 12, King = 13, Ace = 14
}
Comparing with rank == Rank.Ace is more understandable than comparing rank == 14.
Cards could be represented like this:
public class Card
{
public Rank Rank { get; }
public Suit Suit { get; }
public Card(Rank rank, Suit suit)
{
Rank = rank;
Suit = suit;
}
public Card(string s)
{
switch (s[0]) {
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
Rank = (Rank)(s[0] - '0');
break;
case 'T':
Rank = Rank.Ten;
break;
case 'J':
Rank = Rank.Jack;
break;
case 'Q':
Rank = Rank.Queen;
break;
case 'K':
Rank = Rank.King;
break;
case 'A':
Rank = Rank.Ace;
break;
}
switch (s[1]) {
case 'C':
Suit = Suit.Club;
break;
case 'D':
Suit = Suit.Diamond;
break;
case 'H':
Suit = Suit.Heart;
break;
case 'S':
Suit = Suit.Spade;
break;
}
}
}
Note that I added 2 constructors. One allows you to define a card directly by specifying the values. The other one parses a string like "8C" and converts it to corresponding values.
A Hand class allows you to put the scoring methods somewhere and to abstract from bare arrays. Here again 2 constructors.
public class Hand
{
public Hand(params Card[] cards)
{
Cards = cards;
}
public Hand(string s)
{
// E.g. s = "8C TS KC 9H 4S"
string[] parts = s.Split();
Cards = parts
.Select(p => new Card(p))
.ToArray();
}
public Card[] Cards { get; }
public bool IsRoyalFlush()
{
if (Cards[0].Rank != Rank.Ace) {
return false;
}
for (int i = 1; i < Cards.Length; i++) {
if (Cards[i - 1].Rank - Cards[i].Rank != 1) {
return false;
}
}
return true;
}
//TODO: Add more scoring methods.
}
On Code Review the user Glitch presented an already very well-structured game (2048 console game (C#)).
In my answer I suggested even more structure by separating different aspects of the game. It first seems like more works, but once you have established a good structure, it is much easier to work on the code.

Offset command in Revit API

How can I use the offset command in my C# plugin? I have the list of lines/arcs to include in the offset and the offset value. I can't find the command to use.
I thought that the ElementTransformUnit class contains something to do it but it seems that it doesn't...
Thank you
There's no Offset command that I'm aware of, but you could make one pretty easily I think using the ElementTransformUtils.CopyElement method instead. Try something like this:
static ElementId Offset(this Element originalelement, double offsetamount, string offsetdirection)
{
ElementId newelement = null;
Document curdoc = originalelement.Document;
LocationPoint elp = originalelement.Location as LocationPoint;
XYZ elem_location = null;
switch(offsetdirection.ToUpper())
{
default:
break;
case "X":
elem_location = new XYZ(offsetamount, 0.0, 0.0) + elp.Point;
break;
case "Y":
// code for Y
break;
case "Z":
// code for Z
break;
}
try
{
using (Transaction tr_offset = new Transaction(curdoc, "Offsetting element"))
{
tr_offset.Start();
newelement = ElementTransformUtils.CopyElement(curdoc, originalelement.Id, elem_location).FirstOrDefault();
tr_offset.Commit();
}
}
catch (Exception e)
{
Console.WriteLine("Command Failed. See below: \n" + e.StackTrace.ToString());
}
return newelement;
}
might be better if you made a Direction enum or something like that but that should work for your purposes, I think.

How to set an image rating?

In my project, i have to set an image rating value in any format (*.png, *.jpg, *.bmp etc.), and return the value.
I try to use PropertyItem. it doesnt work.
Image im = Image.FromFile("D:\\2.jpg");
int intValue = 3;
byte[] intBytes = BitConverter.GetBytes(intValue);
if (BitConverter.IsLittleEndian)Array.Reverse(intBytes);
byte[] result = intBytes;
PropertyItem prop = im.GetPropertyItem(18246);
prop.Value = result;
im.SetPropertyItem(prop);
Does any one do this, if yes how, thanks?
To set up Rating You have to set up two values. Rating and RatingPercent
Exif.Image.Rating (18246)
Exif.Image.RatingPercent (18249)
These two values are corresponding to each other. So setting just Rating doesn't reflect Rating stars in Windows. (In fact it is very tricky because You set value, You can read it, but in Windows Explorer nothing changes).
class Program
{
static void Main(string[] args)
{
//0,1,2,3,4,5
SetRating(0);
SetRating(1);
SetRating(2);
SetRating(3);
SetRating(4);
SetRating(5);
}
private static void SetRating(short ratingValue)
{
short ratingPercentageValue = 0;
switch (ratingValue)
{
case 0: ratingPercentageValue = ratingValue; break;
case 1: ratingPercentageValue = ratingValue; break;
default: ratingPercentageValue = (short)((ratingValue - 1) * 25); break;
}
string SelectedImage = #"d:\Trash\phototemp\IMG_1200.JPG";
using (var imageTemp = System.Drawing.Image.FromFile(SelectedImage))
{
var rating = imageTemp.PropertyItems.FirstOrDefault(x => x.Id == 18246);
var ratingPercentage = imageTemp.PropertyItems.FirstOrDefault(x => x.Id == 18249);
rating.Value = BitConverter.GetBytes(ratingValue);
rating.Len= rating.Value.Length;
ratingPercentage.Value = BitConverter.GetBytes(ratingPercentageValue);
ratingPercentage.Len = ratingPercentage.Value.Length;
imageTemp.SetPropertyItem(rating);
imageTemp.SetPropertyItem(ratingPercentage);
imageTemp.Save(SelectedImage + "new" + ratingValue +".jpg");
}
}
}
The solution is not optimal (and hackish), but the easiest way is:
1) Use an image on your harddrive. Any image. Just rate it manually, so that the image has this property.
2) This image will work as your "dummy image", so that you can load it in order to call getPropertyItem() on it, to get the property.
3) Once you have the PropertyItem, just change its value, and use SetPropertyItem on your actual image.
string dummyFileName = #"C:\Users\<youruser>\Pictures\dummy.jpg";
string realFileName = #"C:\Users\<youruser>\Pictures\real.jpg";
string realFileNameOutput = #"C:\Users\<youruser\Pictures\real_rated.jpg";
Image dummyFile = Image.FromFile(dummyFileName);
var propertyItem = dummyFile.GetPropertyItem(18246);
Image realImage = Image.FromFile(realFileName);
realImage.SetPropertyItem(propertyItem);
realImage.Save(realFileNameOutput);

Trouble finding tab character in list objects

I am working in C#, winforms application.
I am reading from a text file where each row has fields divided by tabs:
I am putting each row in a list named tic_string. From here I am trying to search each list object, find the tabs, and put each field in its own array. So there will be an array for column a, column b, column c ... etc.
The problem is when I try to find the tabs in my list objects, it finds nothing. Here is my code:
string[] tic_num = new string[row_counter];
string[] tic_title = new string[row_counter];
string[] tic_owner = new string[row_counter];
string[] tic_open_date = new string[row_counter];
int last_tab = 0;
int char_counter = 0;
int feild_counter = 1;
int feild_char_count = 1;
int current_row=0;
string temp_feild = "";
char temp_char;
char tab_char = '\t';
foreach (string tic_string_value in tic_string)
{
temp_char = tic_string_value[char_counter];
if (temp_char == tab_char)
{
Console.WriteLine("tab_found");
if (feild_char_count == 1)
{
temp_feild = "";
}
else
{
temp_feild = tic_string_value.Substring(last_tab, feild_char_count);
}
last_tab = char_counter;
feild_char_count = 0;
switch (feild_counter)
{
case 1:
tic_num[current_row] = temp_feild;
break;
case 2:
tic_title[current_row] = temp_feild;
break;
case 3:
tic_owner[current_row] = temp_feild;
break;
case 4:
tic_open_date[current_row] = temp_feild;
break;
}
}
current_row++;
feild_char_count++;
char_counter++;
if (feild_counter == 5)
feild_counter = 1;
}
Your code seems to be too complicated for such simple task. Do not parse each line char by char, just use helper functions like String.Split etc.:
foreach (string tic_string_value in tic_string)
{
var parts = tic_string_value.Split(new [] { '\t' },
StringSplitOptions.RemoveEmptyEntries);
tic_num[current_row] = parts[0];
tic_title[current_row] = parts[1];
tic_owner[current_row] = parts[2];
tic_open_date[current_row] = parts[3];
current_row++;
}
First of all, I deduce from the style of your code that you are probably familiar with C/C++ and are new to C#, because this code has a particularly "C++" flavour to it. It reminds me very much of my own C# code when I first made the jump myself.
I am glad that you described the problem you are trying to solve rather than simply posting the code and asking where to find the bug because I think you can actually solve your problem much more simply.
Considering the following code (this assumes that you're iterating over each of the rows outside this code, and I omit some of the declaring of variables that you had already specified):
int field_counter = 0;
foreach (var field in tic_string.Split('\t')) {
switch (field_counter++) {
case 0:
tic_num[current_row] = field;
break;
case 1:
tic_title[current_row] = field;
break;
case 2:
tic_owner[current_row] = field;
break;
case 3:
tic_open_date[current_row] = field;
break;
}
}
This leverages the succinctness of C# and removes quite a few lines of code, which is always good. The String.Split method will take care of most of the string splitting for you, so there's no need to do it all manually and keep track of characters.
Note: I kept your original naming of some of the field names, although generally it is preferable to use CamelCase in C# code.
Now I notice from your original code that it's possible you don't have "rows" in your data in an actual sense (i.e. split by newline characters) but rather you may have the data entirely tab separated and are using the fact that you have a fixed number of columns per row to split up rows.
If this was the case, might I suggest the following code block could help you:
int i = 0;
foreach (var group in tic_string.GroupBy(x => i++ % 4)) {
int current_row = 0;
foreach (var field in group) {
switch (group.Key) {
case 0:
tic_num[current_row] = field;
break;
case 1:
tic_title[current_row] = field;
break;
case 2:
tic_owner[current_row] = field;
break;
case 3:
tic_open_date[current_row] = field;
break;
}
current_row++;
}
}
Now of course you may need to adapt these blocks to your code rather than use it verbatim. I hope that they at least demonstrate a different way of thinking about the problem. In particular, learning to use the various LINQ extension methods and LINQ queries will also be very helpful - they are part of what allows C# code to be so quick and easy to develop.
Best of luck in solving your problem!
You could also use a list instead of 4 string arrays:
public class ObjectToBeUsed
{
public Person(int num, string title, string owner, string opendate)
{
this.Num = num;
this.Title = title;
this.Owner = owner;
this.OpenDate = opendate;
}
private int _num;
public int Num
{
get { return _num; }
set { _num = value; }
}
private string _title;
public string Title
{
get { return _title; }
set { _title = value; }
}
private string _owner;
public string Owner
{
get { return _owner; }
set { _owner = value; }
}
private string _opendate;
public string OpenDate
{
get { return _opendate; }
set { _opendate = value; }
}
}
This is the class which describes each row in your text file.
System.IO.StreamReader file = new System.IO.StreamReader("test.txt");
string currentLine = null;
List<ObjectToBeUsed> peopleList = new List<ObjectToBeUsed>();
while ((currentLine = file.ReadLine()) != null)
{
string[] tokens = Regex.Split(currentLine, #"\t");
peopleList.Add(new ObjectToBeUsed(Convert.ToInt32(tokens[0]), tokens[1], tokens[2], tokens[3]));
}
The code is pretty self-explanatory, but if you need any further explaining, go ahead.

Categories

Resources