C# Parse text file - access class field by index - c#

I'd like to parse a text file with a few dozen entries. Right now, I have a dumbed-down solution that reads line by line and compares against hard-coded strings:
while ((line = reader.ReadLine()) != null) //returns null if end of stream
{
cmpStr = "MODE";
try
{
if (line.Equals(cmpStr))
GlobalData.mode = Convert.ToInt32(line.Remove(0, cmpStr.Length));
}
catch { }
cmpStr = "TIME_YEAR";
try
{
if (line.Equals(cmpStr))
GlobalData.time_year = Convert.ToInt32(line.Remove(0, cmpStr.Length));
}
catch { }
// ... repeat to parse the remaining lines
}
GlobalData is a static class and looks like this:
public static class GlobalData
{
public static int mode;
public static int time_year;
public static int time_month;
public static int time_day;
public static int time_hour;
public static int time_minute;
// other entries omitted
public static string[] GlobalKeywords = new string[37]
{
"MODE",
"TIME_YEAR",
"TIME_MONTH",
"TIME_DAY",
"TIME_HOUR",
"TIME_MINUTE",
// other entries omitted
};
}
If it were possible to access my static fields by index, I'd do:
int i = 0;
while ((line = reader.ReadLine()) != null)
{
cmpStr = GlobalData.GlobalKeywords[i]; // when i == 0: cmpStr = "MODE"
if (line.Equals(cmpStr))
GlobalData[i] = Convert.ToInt32(line.Remove(0, cmpStr.Length));
// GlobalData[0] would be GlobalData.mode, and so on (but doesn't work)
i++;
}
catch { }
So, even though I can setup a loop to compare against a string array of keywords,
how do I assign a certain field of my static class ?
br
Chris

I'm not sure what your business constraints are, so it's hard to propose a fool-proof solution, though a few points:
cmpStr = "MODE";
try
{
if (line.Equals(cmpStr))
GlobalData.mode = Convert.ToInt32(line.Remove(0, cmpStr.Length));
}
This won't work as you (probably expect) - if line.Equals("MODE") then line.Remove(0, "MODE".Length) is an empty string. What you probably want is line.StartsWith(cmpStr) or line.Contains(cmpStr).
GlobalData is a static class
This doesn't seem a good approach for what you're doing. You may want to read up on static classes and when to use them (MSDN is a good starting point, though it obviously can't cover everything: http://msdn.microsoft.com/en-us/library/79b3xss3%28v=vs.80%29.aspx).
Other than that, you can probably simply replace all your int fields with a dictionary (though please rethink the static approach as described above):
public static Dictionary<String, int> Items = new Dictionary<String, int>();
Then your parsing code could look like this:
while ((line = reader.ReadLine()) != null) //returns null if end of stream
{
var matchingString
= GlobalData.GlobalKeywords.FirstOrDefault(s => line.StartsWith(s));
if (matchingString != null)
GlobalData[matchingString]
= Convert.ToInt32(line.Remove(0, matchingString.Length));
}
You will then be able to fetch that data using e.g. GlobalData.Items["MODE"].
One last bit: you may consider introducing constant values in your global data class, e.g.:
public const String MODE = "MODE";
Then you can use GlobalData.Items[GlobalData.MODE] and avoid typos: writing GlobalData.Items[GlobalData.MODe] would cause a compile error.

Replace this:
public static int mode;
public static int time_year;
public static int time_month;
public static int time_day;
public static int time_hour;
public static int time_minute;
With this:
public static Dictionary<string, int> my_values = new Dictionary<string, int>();
Then replace:
GlobalData[i] = Convert.ToInt32(line.Remove(0, cmpStr.Length));
with:
GlobalData.my_values[cmpStr] = Convert.ToInt32(line.Remove(0, cmpStr.Length));
That should do what you want even though I don't understand how you expect the Convert.ToInt32 to work. The way you are calling Remove will create an empty string (which might convert to 0, I can't remember) and even if it didn't, the line doesn't contain a number because you compared it successfully to a string like "MODE".

An elegant way to solve your problem is to prepare a different action for each of the acceptable strings. You use a Dictionary(Of String, <Action>) where Action is a common delegate type that receive a string in input and know how to process it accordingly to the keyword present at the beginning of the line.
// The common signature for every methods stored in the value part of the dictionary
public delegate void ParseLine(string line);
// Global dictionary where you store the strings as keyword
// and the ParseLine as the delegate to execute
Dictionary<String, ParseLine> m_Actions = new Dictionary<String, ParseLine>() ;
void Main()
{
// Initialize the dictionary with the delegate corresponding to the strings keys
m_Actions.Add("MODE", new ParseLine(Task1));
m_Actions.Add("TIME_YEAR", new ParseLine(Task2));
m_Actions.Add("TIME_MONTH", new ParseLine(Task3));
m_Actions.Add("TIME_DAY", new ParseLine(Task4));
.....
while ((line = reader.ReadLine()) != null)
{
// Search the space that divide the keyword from the value on the same line
string command = line.Substring(0, line.IndexOf(' ')).Trim();
// a bit of error checking here is required
if(m_Actions.ContainsKey(command))
m_Actions[command](line);
}
}
void Task1(string line)
{
// this will handle the MODE line
GlobalData.Mode = Convert.ToInt32(line.Substring(line.IndexOf(' ')+1).Trim());
}
void Task2(string line)
{
GlobalData.time_year = Convert.ToInt32(line.Substring(line.IndexOf(' ')+1).Trim());
}
void Task3(string line)
{
.....
}
void Task4(string line)
{
.....
}

A simple (and not really clean) approach is to add an indexer to your global data class and decide which field to set based on the index. But you have to extend the indexer every time you add a field (basically you move the if/switch from the while Loop into the indexer).
You could also use reflection, if you can match the keyword to the field name. This is not very performant but does not need to be extended as long as you can map the keyword to the new field name.
Another approach is to create a dictionary>. In this dictionary you register the keywords, e.g. (pseudo-code):
Class Level variable:
private keywordsDict = new Dictionary<string, Action<int>>();
In a constructor:
keywordsDict.Add("MODE", delegate(value) GlobalData.mode = value);
In while-loop:
var action = keywordsDict[line];
action(value);
In the later approach, you only need to extend the dictionary but not the algorithm as such if you have a new keyword/field.

May be i can tell you how to achieve it (GlobalData[i]) in C# thought its not the answer you are looking for.
class GlobalData
{
private string[] array = new string[10];
public GlobalData()
{
//now initialize array
array[0] = "SomeThingA";
array[1] = "SomeThingB";//continue initialization.
}
public string this[int index]
{
get {return array[index];}
}
}
Now the clients can use GlobalData like ,
GlobalData gd = new GlobalData();
gd[1] = "SomeOtherThing" ; //set the value.
string value = gd[1];//get the value
But this cant be done by making the class static as you see it works with 'this'

Related

Class wrapper for data lists

I need some help building a fluent interface (class wrapper) that allows me to create (and name) a 2D double array from curve sets in a database (in myWell). Ideally, a user could create a 2D double array when executing the following syntax (or something similar):
Double [,] CurveDoubleName = CreateIPmathCurves.CreateCurve(comboBox1.Text).CurveName("NPHIL").Make()
Where comboBox1 data comes from a WindowsForm called frmMain. Here's what I have so far:
namespace UserProgram
{
public class CreateIPmathCurve : frmMain, ICanNameCurve, ICanLocateCurve, ICanMakeCurve
{
private string _comboBoxName;
private string _CurveName;
private string _data;
// Private constructor - Only allow instantiated functions to create an IP math Curve
private CreateIPmathCurve()
{ }
// Instantiating functions
public static ICanNameCurve CreateCurve()
{
return new CreateIPmathCurve();
}
// Chaining functions
private CreateIPmathCurve(string data) { _data = data; } //private constructor prevents instantiation of your builder
public ICanLocateCurve SetCurveName(string CurveName)
{
_CurveName = CurveName;
return this; // this allows chaining.
}
public ICanMakeCurve SetComboBoxName(string comboBoxName)
{
_comboBoxName = comboBoxName;
return this; // this allows chaining.
}
// ending functions
public DataObject CreateCurveDoublArrayObj(string comboBoxName)
{
try
{
// User will need to populate comboBox.. example: comboBox1.text
char[] delimiter = { ':' };
Curve1inText = comboBoxName;
string[] crvIn1 = Curve1inText.Split(delimiter);
string CurveSet = crvIn1[0];
string Curve = crvIn1[1];
ICurveSet InCurveSet = myWell.FindCurveSet(CurveSet);
ICurve InMyCurve = myWell.FindCurve(Curve);
if (InMyCurve == null)
{
MessageBox.Show("You need to input a curve");
}
ILogReading[] In = InMyCurve.LogReadings.ToArray();
double[,] CurveDouble = new double[In.Length, 2];
int j = 0;
foreach (ILogReading reading in InMyCurve.LogReadings)
{
CurveDouble[j, 0] = reading.Depth;
CurveDouble[j, 1] = reading.Value;
j++;
}
return new DataObject(CurveDouble);
}
catch (Exception ex)
{
MessageBox.Show("Error building Double Array\n" + ex.Message + "\n" + ex.StackTrace);
return null;
}
}
public double[,] MakeCurve()
{
//this is where CurveName input ("NPHIL") should name the 2D double array listed from dataobject.
// I receive a "non-invocable member 'DataObject' cannot be used like a method" error....
_CurveName = DataObject(_comboBoxName);
return this;
// I also receive a "cannot implicity convert type UserProgram.CreateIPmathCurve' to 'double [*,*]"...
}
}
// using interfaces to enforce Fluent Interface grammar -- can't make curve if you don't know the location of curve, etc...
public interface ICanNameCurve
{
ICanLocateCurve SetCurveName(string CurveName);
}
public interface ICanLocateCurve
{
ICanMakeCurve SetComboBoxName(string comboBoxName);
}
public interface ICanMakeCurve
{
DataObject CreateCurveDoublArrayObj(string comboBoxName);
}
}
Can you help me create a CurveName() function that would allow the user to name the dataobject? (I tried a getter-setter accessor, but I don't think I was doing it correctly or am lacking a strong conceptual understanding of how it all works)
Lastly, can you also help me create a Make() function that puts all of this together?
To build a fluent API, you need to find a way to aggregate all data until your call to Make.
A simple way is to write a Builder, which holds all data. This builder has setter methods for every configurable field.
The key point here is that each setter method returns the Builder object, allowing you to chain calls.
public class FluentCurveBuilder
{
private string _name;
private string _data;
private string _color;
private FluentCurveBuilder(string data) { _data = data; } // private constructor prevents instantiation of your builder
public FluentCurveBuilder SetName(string name)
{
_name = name;
return this; // this allows chaining.
}
public FluentCurveBuilder SetColor(string color)
{
_color = color;
return this; // this allows chaining.
}
public static FluentCurveBuilder CreateCurve(string data)
{
return new FluentCurveBuilder(data);
}
public Curve Make()
{
// Creation logic goes here
}
}
You now can use the builder to configure your curve.
var curve = FluentCurveBuilder.CreateCurve("Data")
.SetName("Test")
.Make();
We have a static CreateCurve method, which returns a new builder. All other methods should only store the data in an instance field and return this builder.
In the Make method, you now have access to all previous aggregated data and you can construct your Curve
I think I was over analyzing my problem - The simple solution would be to create a method that returns the 2D double array and then assign a name to the object when I invoke the function... so using this:
public double [,] CreateIPmathCurve(string comboBoxName)
{
string CurveInText = "";
char[] delimiter = { ':' };
CurveInText = comboBoxName;
string[] crvIn = CurveInText.Split(delimiter);
string CurveSet = crvIn[0];
string Curve = crvIn[1];
ICurveSet InCurveSet = myWell.FindCurveSet(CurveSet);
ICurve InMyCurve = myWell.FindCurve(Curve);
if (InMyCurve == null)
{
MessageBox.Show("You need to input a curve");
}
ILogReading[] In = InMyCurve.LogReadings.ToArray();
double[,] CurveDouble = new double[In.Length, 2];
int j = 0;
foreach (ILogReading reading in InMyCurve.LogReadings)
{
CurveDouble[j, 0] = reading.Depth;
CurveDouble[j, 1] = reading.Value;
j++;
}
return CurveDouble;
Allows me to create the array with this:
double[,] NPHIL = CreateIPmathCurve(comboBox1.Text);
Thanks to everyone who helped me in this endeavor!

The out parameter must be assigned to before control leaves the current methods

I'm very new C# and this is the first time I'm doing anything with a list, so this might be a very dumb question... I'm trying to read data from a file to a list that consists of Tourist objects. As I understand I need to assign something to tourists list before I add objects to it, but I'm not sure how to do that.
class Tourist
{
public string FirstName { get; set; }
public string LastName { get; set; }
public double Contributed { get; set; }
public Tourist(string firstName, string lastName, double money)
{
FirstName = firstName;
LastName = lastName;
Contributed = money * 0.25;
}
}
class Program
{
static void Main(string[] args)
{
List<Tourist> tourists = new List<Tourist>();
ReadData(out tourists);
}
static void ReadData(out List<Tourist> tourists)
{
const string Input = "..\\..\\Duomenys.txt";
string[] lines = File.ReadAllLines(Input);
foreach (string line in lines)
{
string[] values = line.Split(';');
string firstName = values[0];
string lastName = values[1];
double money = Double.Parse(values[2]);
tourists.Add(new Tourist(firstName, lastName, money));
}
}
}
By declaring a parameter as out you "promise" the caller (and the compiler) that your method will set a value to the variable provided as argument for that parameter.
Because you promise it, every path through your method must assign a value to this parameter.
Your method does not assign a value to tourists. This may actually lead to a NullReferenceException at tourists.Add(...) if the method gets called with a null reference.
To me it seems you can ommit the out keyword as you initialize tourists already in Main. Note that ReadData only modifies the content of the list, not the reference to it stored in the tourists variable. Since you don't want to change that reference (the variable's value), you don't need the out keyword.
If you want ReadData to initialize it, you need to add the line
tourists = new List<Tourist>()
in ReadData before the foreach loop.
As your code stands, the better solution is to ommit any parameter to ReadData and let the method return the list instead:
static List<Tourist> ReadData()
{
// create list
List<Tourist> tourists = new List<Tourist>();
const string Input = "..\\..\\Duomenys.txt";
string[] lines = File.ReadAllLines(Input);
foreach (string line in lines)
{
// shortened for brevity
tourists.Add(new Tourist(firstName, lastName, money));
}
return tourists; // return newly created list
}
And use this in Main like:
static void Main(string[] args)
{
List<Tourist> tourists = ReadData();
}
Parameters with out need to be assigned to in the body of the method and do not get their value carried over from the call site. Quoting msdn:
Within a method, just like a local variable, an output parameter is initially considered unassigned and must be definitely assigned before its value is used.
In your case there are three ways to solve it:
First, you can move assignment from caller to the method:
static void Main(string[] args)
{
List<Tourist> tourists;
ReadData(out tourists);
}
static void ReadData(out List<Tourist> tourists)
{
tourists = new List<Tourist>();
//...
}
Second, you can change your declaration to skip out in the declaration entirely, which will carry the initiated value to the method and lift the requirement to assign it in that method.
Last option (and the best one IMO, in terms of readability) is to make the list a return value instead of out parameter:
static void Main(string[] args)
{
List<Tourist> tourists = ReadData();
}
static List<Tourist> ReadData()
{
List<Tourist> tourists = new List<Tourist>();
//...
return tourists;
}
You have to provide a value for your out-parameter before leaving the method
static void ReadData(out List<Tourist> tourists)
{
const string Input = "..\\..\\Duomenys.txt";
tourists = new List<Tourist>();
string[] lines = File.ReadAllLines(Input);
foreach (string line in lines)
{
string[] values = line.Split(';');
string firstName = values[0];
string lastName = values[1];
double money = Double.Parse(values[2]);
tourists.Add(new Tourist(firstName, lastName, money));
}
}
However as you´re passing a List<T> which is a reference-type you don´t need the out.keyword as modifications to the object that you´re referencing are reflected in all references.
So after calling ReadData the list you´ve provided will change also:
var tourists = new List<Tourist>();
ReadData(toursists); // this changes the elements within the list
// do something with the list

C# fields not retaining values when stored in arrays

I have a situation in my program where I have around 20 fields. All of them are strings. Now I also have an array of strings of size 20. I want to sequentially initialize those fields from the string stored inside this array. I do not want to do this:
field1 = array[0];
field2 = array[1];
....
field20 = array[19];
So I wrote a test program like this but it doesn't work with strings. It's only working with reference types. Is there any way to do it?
public class Program
{
private string name;
private string id;
private void Func()
{
var array = new[] {name, id};
for (int i = 0; i < array.Length; i++)
{
array[i] = "some string";
}
}
public static void Main(string[] args)
{
var p = new Program();
p.Func();
Console.WriteLine(p.name); // prints null
}
}
The assumptions about the behavior are incorrect.
// Create a NEW array with the specified expressions which are evaluated
// immediately (to the current values of the fields)..
var array = new[] {name, id};
// Meaning it is equivalent to this .. note that the field names have
// NOTHING to do with the array object itself.
var array = new[] {(string)null, (string)null};
// Then for each item in the array, assign it a value
// (replacing what was already there anyway)
for (int i = 0; i < array.Length; i++) {
array[i] = "some string";
}
And at the end we end up with an array that looks like ["some string", "some string"]. Again, there is no "connection" with the fields. This issue has naught to do with reference types or not (and strings are also reference types).
The best (and usually correct) way is honestly to do it a different way. Although one could wrap field access/setters and there is always reflection.. If dynamic names are truly required then a Dictionary or similar should probably be used instead
Here is a method using a proxies to wrap the assignment operations. This example uses Actions and "Statement Lambda" syntax.
var setters = new Dictionary<string, Action<Program, string>>() {
{ "name", (p, value) => p.name = value },
{ "id", (p, value) => p.id = value },
};
// For each field setter, assign a value (could use the name as a look-up)
foreach (var setter in setters.Values) {
setter(this, "some string");
}
This works because setter(..) invokes the action defined earlier that actually assigns to the appropriate member. Using such a look-up/proxy (using actions, functions, or more complex types) is a valid approach for some situations, but should probably be avoided when not needed.
This can also be done with Reflection.
var t = this.GetType();
var fieldNames = new [] { "name", "id" };
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
foreach (var name in fieldNames) {
var fieldInfo = t.GetField(name, bindingFlags);
fieldInfo.SetValue(this, "some string");
}
Reflection should generally be a "method of last resort". It loses static typing information, pushes off many errors until run-time, and carries a performance penalty (that, granted, likely doesn't matter). There are some really nifty things that can be done (especially when Expressions and Annotations are also used) .. but reflection is magic best left until it's really needed.
See if this is what you are trying to achieve:
public class Program
{
private string name;
private string id;
private Dictionary<string, int> mapper = new Dictionary<string, int>();
private String[] array= null;
public Program()
{
mapper.Add("name", 1);
mapper.Add("id", 2);
}
public string Name
{
get { return array[mapper["name"]]; }
}
public string Id
{
get { return array[mapper["id"]]; }
}
private void Func()
{
array = new[] { name, id };
for (int i = 0; i < array.Length; i++)
{
array[i] = "some string";
}
}
public static void Main(string[] args)
{
var p = new Program();
p.Func();
Console.WriteLine(p.name); // prints null
}
}

What is the proper way to return two char arrays as a single string?

I have a public property in a static class which I want to use as a means of validating the user's input against illegal file and path names.
At present I have this:
private static string invalidFileNames = new string(Path.GetInvalidFileNameChars());
private static string invalidPathNames = new string(Path.GetInvalidPathChars());
private static string invalidUserInput = (invalidFileNames + invalidPathNames);
public static string InvalidUserInput
{
get { return invalidUserInput; }
}
Based on Microsoft's documentation here I am expecting to get back "<>|"<>| But all I am getting is the first "<>|.
Can anyone shed some light as to what is happening here? How do I ensure that I get both strings returned?
You could just make it a single string
using System.Linq;
public static string InvalidUserInput
{
get
{
return new string(Path.GetInvalidFileNameChars()
.Concat(Path.GetInvalidPathChars())
.Distinct()
.ToArray());
}
}
You wont see them all in a TextBox because of the terminator type chars in InvalidUserInput in your case its the \0(null teminator) that its stopping the display.
if you want to display just the ones that make sense to the user you can strip out the ones that cause the issue using Char.IsControl
Here is a static class to wrap it all up
public static class StringExtentions
{
private static string _invalidUserInput = string.Empty;
private static string _PrinatbleInvalidUserInput = string.Empty;
public static string InvalidUserInput
{
get
{
if (_invalidUserInput == string.Empty)
{
_invalidUserInput = new string(Path.GetInvalidFileNameChars()
.Concat(Path.GetInvalidPathChars())
.Distinct()
.ToArray());
}
return _invalidUserInput;
}
}
public static string GetPrinatbleInvalidUserInput
{
get
{
if (_PrinatbleInvalidUserInput == string.Empty)
{
_PrinatbleInvalidUserInput = new string(InvalidUserInput.Where(x => !char.IsControl(x)).ToArray());
}
return _PrinatbleInvalidUserInput;
}
}
public static bool IsValidUserInput(this string str)
{
return !str.Any(c => InvalidUserInput.Contains(c));
}
}
usage:
public MainWindow()
{
InitializeComponent();
string myString = "C:\\InvalidPath<";
if (!myString.IsValidUserInput())
{
MessageBox.Show(string.Format("String cannot contain {0}", StringExtentions.GetPrinatbleInvalidUserInput));
}
}
You can't see them in debugger, but you can output them to the file and see them with some better editor than notepad, like notepad++
File.WriteAllText("tmp.txt", invalidUserInput, UTF8Encoding.GetEncoding("UTF-8"));
In this case, because you are presumably going to be using the data numerous times, you would want to only record characters that are unique between both character arrays. To do this, you can use the Union method as follows:
private static string invalidUserInput = new string(Path.GetInvalidFileNameChars().Union(Path.GetInvalidPathChars()).ToArray());
Running your code gives a number of unicode characters returned:
"<>|□□□□□□□□□
□□
□□□□□□□□□□□□□□□□□□:*?\/"<>|□□□□□□□□□
□□
□□□□□□□□□□□□□□□□□□
Are you sure that you are not loosing anything due to the unicode characters?
Also, is that your exact code? If you switch the ordering of the variable initalizations it will no longer work as invalidUserInput must be evaluated after the other two (they are evaluated in the order they are defined in the code).

Adding values to a C# array from a different class

I'm trying to add new values input by the user on a separate windows form into the following array:
public class NameValue
{
public string Name;
public string Value;
public NameValue() { Name = null; Value = null; }
public NameValue(string name, string value) { Name = name; Value = value; }
}
public class DefaultSettings
{
public static NameValue[] Sites = new NameValue[]
{
new NameValue("los angeles, CA", "http://losangeles.craigslist.org/"),
};
public static NameValue[] Categories = new NameValue[]
{
new NameValue("all for sale", "sss"),
};
}
How do I add the new values to the array while keeping the values of the old array?
Edit
I tried using Mr. Noren's function:
static void AddValueToSites(NameValue newValue)
{
int size = DefaultSettings.Sites.Length;
NameValue[] newSites = new NameValue[size + 1];
Array.Copy(DefaultSettings.Sites, newSites, size);
newSites[size] = newValue;
DefaultSettings.Sites = newSites;
}
private void button1_Click(object sender, EventArgs e)
{
NameValue newSite = new NameValue("Test, OR", "http://portland.craigslist.org/");
AddValueToSites(newSite);
Close();
}
But that's not working... The class I am getting data from is:
public partial class Location : Office2007Form
{
public Location()
{
InitializeComponent();
}
static void AddValueToSites(NameValue newValue)...
private void button1_Click(object sender, EventArgs e)...
}
You cannot change the size of an array, ever. You would need to use something like a List for that.
Since you're using name/value pairs you should consider using Dictionary<TKey,TValue>.
Finally, if you're looking to have different classes contribute to the contents of the arrays, then that's not going to happen.
You can't add to an array, whether it's in another class or not.
Use List<NameValue> instead of NameValue[] and then you can use Sites.Add(...).
If you're absolutely married to the idea of using an array versus some more flexible collection, you should implement some AddX() methods in the class that is defining the base values. Those methods would take care of inserting the new values in the array. If you're not concerned with multithreading issues, it can be very simple:
(Warning: code is from my head and not tested)
static void AddValueToSites(NameValue newValue)
{
int size = Sites.Length;
NameValue[] newSites = new NameValue[size+1];
Array.Copy(Sites, newSites, size);
newSites[size] = newValue;
Sites = newSites;
}
And again for Categories.
Like others suggested, using List<NameValue> or Dictionary<string,string> would be options that would be more fluid. These already have Add, Remove, Contains, etc. - basically all you need when you need to manipulate arrays.
Arrays are not mutable in place, so if you resize them (using any approach) it'll result in a different instance being created (this is what happens in VB.NET's ReDim but they hide it from you).
The simplest way to resize an array in C# is to use the Concat extension method (requires System.Linq):
string[] myArray = new string[] { "Hello", "World" };
myArray = myArray.Concat(new string[] { "Something", "new" };
myArray will now be 4 elements deep. I don't think this will work between classes though (haven't tried though).

Categories

Resources