ArrayList of Hashtables in C# - c#

I want to have an ArrayList where it contains HashTables. I create a Hashtable and added values. I then added it to the ArrayList. I then changed the values of the Hashtables and added it again the Array List. It does not save the first values and ending having duplicated values which were exactly the same as the last values!
Any suggestions? Here is my code
namespace ValuesTest
{
internal class Class1
{
public static ArrayList StartList = new ArrayList();
public static Hashtable Start = new Hashtable();
static void Main(string[] args)
{
Start["active"] = true;
Start["name"] = "prog1";
Start["path"] = #"C:\programfiles\prog1";
Start["parameter"] = string.Empty;
StartList.Add(Start);
Start["active"] = false;
Start["name"] = "prog2";
Start["path"] = #"C:\programfiles\prog2";
Start["parameter"] = "/q";
StartList.Add(Start);
foreach (Hashtable HT in StartList)
{
Console.WriteLine(HT["active"] + " - " + HT["name"] + " - " + HT["path"] + " - " + HT["parameter"]);
// it will always gives
// False - prog2 - C:\programfiles\prog2 - /q
}
Console.ReadLine();
}
}
}

Move start to inside your Main function, and reinitialize it for the second add(and as #lasseespeholt said use List<T>).
static List<Hashtable> StartList = new List<Hashtable>();
static void Main(string[] args)
{
Hashtable Start = new Hashtable();
Start["active"] = true;
Start["name"] = "prog1";
Start["path"] = #"C:\programfiles\prog1";
Start["parameter"] = string.Empty;
StartList.Add(Start);
Start = new Hashtable();
Start["active"] = false;
Start["name"] = "prog2";
Start["path"] = #"C:\programfiles\prog2";
Start["parameter"] = "/q";
StartList.Add(Start);

You're modifying the one and only Start Hashtable object, you must create a new one:
Start = new Hashtable();
right after the first:
StartList.Add(Start);
Remember, you're only adding a reference to the object to the ArrayList: so what your code does is: populate a hashtable, add a reference to it to the list, modify it some more, and add the same reference again.
Would like to add, why are you using a hashtable? It would be far better to use a new class with the fields you desire - then they could have a PrintInfo, or a ToString override that gets the information you need - and presumably an Execute method.

Some more feedback on this: Although Nix already answered your question, I'd drop Hashtable as well (just as ArrayList it's dated), although your concept doesn't lend itself nice to it: You store string to object..
So, copying and changing we'd end up with
static void Main(string[] args)
{
Dictionary<string, object> Start = new Dictionary<string, object>();
Start["active"] = true;
Start["name"] = "prog1";
Start["path"] = #"C:\programfiles\prog1";
Start["parameter"] = string.Empty;
StartList.Add(Start);
Dictionary<string, object> Start = new Dictionary<string, object>();
Start["active"] = false;
Start["name"] = "prog2";
Start["path"] = #"C:\programfiles\prog2";
Start["parameter"] = "/q";
StartList.Add(Start);
But I'd go further: If you just want to spawn processes, that's what the class Process is for. It keeps just the same information (except for "active") in the StartInfo property.
Another, (better?) approach would be to create a value class for this set of information:
class YourStartInfo
{
public bool Active { get; set; }
public string Name { get; set; }
public string Path { get; set; }
public string Parameter { get; set; }
}
and changing your code to make use of that:
static List<YourStartInfo> StartList = new List<YourStartInfo>();
static void Main(string[] args)
{
StartList.Add(new YourStartInfo {
Active = true,
Name = "prog1",
Path = #"C:\programfiles\prog1";
Parameter = string.Empty
});
StartList.Add(new YourStartInfo {
Active = false,
Name = "prog2",
Path = #"C:\programfiles\prog2";
Parameter = "/q"
});
foreach (YourStartInfo startInfo in StartList)
{
// Access the information in a sane way, not as object here
if (startInfo.Active)
{
// Probably launch it?
}
}
Console.ReadLine();
}

Related

Filepath not found outside WPF window ctor

I am using following world heatmap in my WPF application:
https://lvcharts.net/App/examples/v1/wpf/GeoHeatMap
//Geomap
private static string GEOMAP_PATH = System.IO.Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory) + "\\Materials\\GeoMaps\\World.xml";
public MainMaterialWindow()
{
//Default application initialization
InitializeComponent();
//geomap chart
var values = new Dictionary<string, double>();
foreach (actual_headmapdata data in GetWorldHeadmapData())
{
values[data.isocode] = data.count;
}
geoMap1.HeatMap = values;
var lang = new Dictionary<string, string>();
lang["DE"] = "Germany"; // change the language if necessary
geoMap1.LanguagePack = lang;
geoMap1.Source = GEOMAP_PATH;
}
What I don't understand is why the filepath is not found if I do something like this.
//Geomap
private static string GEOMAP_PATH = System.IO.Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory) + "\\Materials\\GeoMaps\\World.xml";
public MainMaterialWindow()
{
//Default application initialization
InitializeComponent();
//init GeoMap
initGeoMap();
}
public void initGeoMap() {
//geomap chart
var values = new Dictionary<string, double>();
foreach (actual_headmapdata data in GetWorldHeadmapData())
{
values[data.isocode] = data.count;
}
geoMap1.HeatMap = values;
var lang = new Dictionary<string, string>();
lang["DE"] = "Germany"; // change the language if necessary
geoMap1.LanguagePack = lang;
geoMap1.Source = GEOMAP_PATH;
}
I get: System.IO.FileNotFoundException: "This file was not found."
So the problem is, why the filepath is not valid anymore once the initialization of the geomap is outside of MainMaterialWindow(). File still exits.
XAML:
<lvc:GeoMap x:Name="geoMap1" HeatMap="{Binding Values}" LanguagePack="{Binding LanguagePack}" Margin="10,0,-12,22" />
Same happens with full filepath as string: GEOMAP_PATH="D:\\Dev\\projectname\\bin\\debug\\Materials\\GeoMaps\\World.xml"
This also only works within MainMaterialWindow(), so it is not about:
private static string GEOMAP_PATH = System.IO.Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory)

Comparing N Objects In A Complex Structure C#

I have a set of instances of the Data class that I want to compare.
Each instance has an unknown number of items in it's Files property.
I want to compare each instance of Data to the others and set FoundDifference to true if a version difference is found between two files with the same Name value.
Is there a simple algorithm to accomplish this?
Here is a sample setup of how the objects might look.
In this example you'd want everything except for f1, f21, and f31 to set the FoundDifference to true
class Data
{
public string DC { get; set; }
public List<File> Files { get; set; }
}
class File
{
public string Name { get; set; }
public string Version { get; set; }
public bool FoundDifference { get; set; }
}
class Program
{
static void Main(string[] args)
{
Data d1 = new Data();
d1.DC = "DC1";
File f1 = new File();
f1.Name = "File1";
f1.Version = "1";
d1.Files.Add(f1);
File f2 = new File();
f2.Name = "File2";
f2.Version = "1";
d1.Files.Add(f2);
File f3 = new File();
f3.Name = "File3";
f3.Version = "1";
d1.Files.Add(f3);
//Another
Data d2 = new Data();
d2.DC = "DC2";
File f21 = new File();
f21.Name = "File1";
f21.Version = "1";
d2.Files.Add(f21);
File f22 = new File();
f22.Name = "File2";
f22.Version = "2";
d2.Files.Add(f22);
File f23 = new File();
f23.Name = "File3";
f23.Version = "1";
d2.Files.Add(f23);
//Another
Data d3 = new Data();
d3.DC = "DC3";
File f31 = new File();
f31.Name = "File1";
f31.Version = "1";
d3.Files.Add(f31);
File f32 = new File();
f32.Name = "File2";
f32.Version = "2";
d3.Files.Add(f32);
File f33 = new File();
f33.Name = "File3";
f33.Version = "5";
d3.Files.Add(f33);
//How Can I change All Files FoundDifference prop to true if FileName is the same and a difference is in Version is found??
Console.ReadLine();
}
I'd handle that by using a Dictionary<string, List<File>> to keep track of the files from each Data like this. First iterate all the files in all the datas then lookup the file name in the dictionary and if not found create a new list and add it. Then check if that list has any files with a different version. If one is found set all the flags and finally add the file to the list.
public void SetDifferences(IEnumerable<Data> datas)
{
var fileLookup = new Dictionary<string, List<File>>();
foreach(var file in datas.SelectMany(d => d.Files))
{
if(!fileLookup.TryGetValue(file.Name, out var fileList))
{
fileList = new List<File>();
fileLookup.Add(file.Name, fileList);
}
if(fileList.Any(f => f.Version != file.Version))
{
foreach(var other in fileList)
{
other.FoundDifference = true;
}
file.FoundDifference = true;
}
fileList.Add(file);
}
}

C# Adding an array or list into an List

I've got a List of Document
public class Document
{
public string[] fullFilePath;
public bool isPatch;
public string destPath;
public Document() { }
public Document(string[] fullFilePath, bool isPatch, string destPath)
{
this.fullFilePath = fullFilePath;
this.isPatch = isPatch;
this.destPath = destPath;
}
The fullFilepath should a List or an Array of Paths.
For example:
Document 1
---> C:\1.pdf
---> C:\2.pdf
Document 2
---> C:\1.pdf
---> C:\2.pdf
---> C:\3.pdf
etc.
My problem if I am using an array string all Documents got "null" in its fullFilePath.
If I'm using a List for the fullFilePath all Documents got the same entries from the last Document.
Here is how the List is filled:
int docCount = -1;
int i = 0;
List<Document> Documents = new List<Document>();
string[] sourceFiles = new string[1];
foreach (string file in filesCollected)
{
string bc;
string bcValue;
if (Settings.Default.barcodeEngine == "Leadtools")
{
bc = BarcodeReader.ReadBarcodeSymbology(file);
bcValue = "PatchCode";
}
else
{
bc = BarcodeReader.ReadBacrodes(file);
bcValue = "009";
}
if (bc == bcValue)
{
if(Documents.Count > 0)
{
Array.Clear(sourceFiles, 0, sourceFiles.Length);
Array.Resize<string>(ref sourceFiles, 1);
i = 0;
}
sourceFiles[i] = file ;
i++;
Array.Resize<string>(ref sourceFiles, i + 1);
Documents.Add(new Document(sourceFiles, true,""));
docCount++;
}
else
{
if (Documents.Count > 0)
{
sourceFiles[i] = file;
i++;
Array.Resize<string>(ref sourceFiles, i + 1);
Documents[docCount].fullFilePath = sourceFiles;
}
}
}
You are using the same instance of the array for every document. The instance is updated with a new list of files at every inner loop, but an array is a reference to an area of memory (oversimplification, I know but for the purpose of this answer is enough) and if you change the content of that area of memory you are changing it for every document.
You need to create a new instance of the source files for every new document you add to your documents list. Moreover, when you are not certain of the number of elements that you want to be included in the array, it is a lot better to use a generic List and remove all that code that handles the resizing of the array.
First change the class definition
public class Document
{
public List<string> fullFilePath;
public bool isPatch;
public string destPath;
public Document() { }
public Document(List<string> fullFilePath, bool isPatch, string destPath)
{
this.fullFilePath = fullFilePath;
this.isPatch = isPatch;
this.destPath = destPath;
}
}
And now change your inner loop to
foreach (string file in filesCollected)
{
string bc;
string bcValue;
....
if (bc == bcValue)
{
List<string> files = new List<string>();
files.Add(file);
Documents.Add(new Document(files, true, ""));
docCount++;
}
else
Documents[docCount].fullFilePath.Add(file);
}
Notice that when you need to add a new Document I build a new List<string>, add the current file and pass everything at the constructor (In reality this should be moved directly inside the constructor of the Document class). When you want to add just a new file you could add it directly to the public fullFilePath property
Moving the handling of the files inside the Documents class could be rewritten as
public class Document
{
public List<string> fullFilePath;
public bool isPatch;
public string destPath;
public Document()
{
// Every constructory initializes internally the List
fullFilePath = new List<string>();
}
public Document(string aFile, bool isPatch, string destPath)
{
// Every constructory initializes internally the List
fullFilePath = new List<string>();
this.fullFilePath.Add(aFile);
this.isPatch = isPatch;
this.destPath = destPath;
}
public void AddFile(string aFile)
{
this.fullFilePath.Add(aFile);
}
}
Of course, now in you calling code you pass only the new file or call AddFile without the need to check for the list initialization.
The issue should be here:
string[] sourceFiles = new string[1];
If you move this line of code in your foreach you should solve this problem because in your foreach you always use the same variable, so the same reference.
int docCount = -1;
int i = 0;
List<Document> Documents = new List<Document>();
foreach (string file in filesCollected)
{
string[] sourceFiles = new string[1];
string bc;
string bcValue;
if (Settings.Default.barcodeEngine == "Leadtools")
{
bc = BarcodeReader.ReadBarcodeSymbology(file);
bcValue = "PatchCode";
}
else
{
bc = BarcodeReader.ReadBacrodes(file);
bcValue = "009";
}
if (bc == bcValue)
{
if(Documents.Count > 0)
{
Array.Clear(sourceFiles, 0, sourceFiles.Length);
Array.Resize<string>(ref sourceFiles, 1);
i = 0;
}
sourceFiles[i] = file ;
i++;
Array.Resize<string>(ref sourceFiles, i + 1);
Documents.Add(new Document(sourceFiles, true,""));
docCount++;
}
else
{
if (Documents.Count > 0)
{
sourceFiles[i] = file;
i++;
Array.Resize<string>(ref sourceFiles, i + 1);
Documents[docCount].fullFilePath = sourceFiles;
}
}
}

Dynamic Array to MS SQL Database

private void getRRvalue(string DELRRNO)
{
try {
DBSFCDataContext SFC = new DBSFCDataContext();
var query = (from i in SFC.POP10500s where i.POPRCTNM == DELRRNO select new { PONO = i.PONUMBER, DATEREC = i.DATERECD, VENDID = i.VENDORID, ITEMCODE = i.ITEMNMBR, QTYBAGS = i.QTYBAGS, QTYSHIP = i.QTYSHPPD, DEPT = i.TRXLOCTN });
foreach (var r in query)
{
string[] row = {
DELRRNO,
r.PONO,
Convert.ToDateTime(r.DATEREC).ToString(),
r.VENDID,
r.ITEMCODE,
r.QTYBAGS.ToString(),
r.QTYSHIP.ToString(),
r.DEPT
};
//glbVariables.getRRNO = ;
//glbVariables.getPONO = ;
//glbVariables.getRRdateRec = ;
//glbVariables.getVendID = ;
//glbVariables.getItemNO = ;
//glbVariables.getQtyBags = ;
//glbVariables.getQtyShipped = ;
//glbVariables.getLocnCode = ;
}
SFC.Connection.Close();
}
catch (Exception ex)
{ MessageBox.Show(ex.Message.ToString()); }
}
I'm new to C#.NET and I was just thinking if I could use a dynamic array like for this code above do I need to declare a global array like this --> "public static string[] row;" so I can use this array string in another form by calling it with the data that I have stored from this function, could this happen in c#?
I need help here please anyone that is good at arrays in c#...
To get you desired results, you will have to do little more work. I explain your solution using List.
First create a class for your one query result:
public class OneRowData
{
public string DELRRNO;
public string PONO;
public string DATEREC;
public string VENDID;
public string ITEMCODE;
public string QTYBAGS;
public string QTYSHIP;
public string DEPT;
}
In your given code, create a List of OneRowData type and make it public static to access it from outside the class as well:
public static List<OneRowData> QueryResults = new List<OneRowData>();
Now in your foreach loop, create an object of OneRowData, assing values to it and add it to the List:
foreach (var r in query)
{
OneRowData Obj = new OneRowData();
//assing values to them
Obj.DATEREC = Convert.ToDateTime(r.DATEREC).ToString();
Obj.DELRRNO = DELRRNO;
Obj.DEPT = r.DEPT;
Obj.ITEMCODE = r.ITEMCODE;
Obj.PONO = r.PONO;
Obj.QTYBAGS = r.QTYBAGS.ToString();
Obj.QTYSHIP = r.QTYSHIP.ToString();
Obj.VENDID = r.VENDID;
//then add the object to your list
QueryResults.Add(Obj);
}
Now you can simply call your List any where and fetch your data like this:
foreach (OneRowData Row in QueryResults)
{
//Row.DATEREC
//Row.DELRRNO
//call them like this and use as you need
}

Dictionary stopping at loadingfromscreen

I run the code and it will not store the values it stops immediately at the loadingfromscreen. What its supposed to do is a multi-page application form that will reinput the values to the texbox's on the back button from the next form.
The ASP.net code is too long to post, but basically its just texbox's and dropboxes. If needed i can post it, but the main issue im 90% sure is the C# code.
UPDATE: When i say stop it continues the code but will not run the dictionary method...i have put a arrow where the method stops in DICTIONARY ONLY
C#:
public partial class employment_driversapplication_personalinfo : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Dictionary<string, string> DriversApplicationData = (Dictionary<string, string>) Session["DriversApp"];
try
{
if (Page.IsPostBack)
{
LoadMemoryFromScreen(DriversApplicationData);
}
else
{
LoadScreenFromMemory(DriversApplicationData);
}
}
catch //(Exception ex)
{
// throw new Exception("Exception occured in employment_driversapplication_personalinfo.aspx - Page_Load" + ex.Message);
}
finally
{
}
}
private void LoadMemoryFromScreen(Dictionary<string, string> DicDriversApp)
{
DicDriversApp["position"] = position.Text; <---Stops here (won't even store this)
DicDriversApp["fname"] = fname.Text;
DicDriversApp["middleinitial"] = middleinitial.Text;
DicDriversApp["lname"] = lname.Text;
DicDriversApp["birthday"] = birthday.Text;
DicDriversApp["proofofage"] = proofofage.SelectedValue;
DicDriversApp["address"] = address.Text;
DicDriversApp["city"] = city.Text;
DicDriversApp["state"] = state.Text;
DicDriversApp["email"] = email.Text;
DicDriversApp["phone"] = phone.Text;
DicDriversApp["altphone"] = altphone.Text;
DicDriversApp["citizen"] = citizen.SelectedValue;
DicDriversApp["whoreferred"] = whoreferred.Text;
DicDriversApp["famfriend"] = famfriend.Text;
DicDriversApp["relationship"] = relationship.Text;
DicDriversApp["rateofpayexpected"] = rateofpayexpected.Text;
DicDriversApp["rateofpaytype"] = RadioButtonList1.SelectedValue;
DicDriversApp["employedNow"] = employednow.SelectedValue;
DicDriversApp["curremployment"] = curremployment.Text;
DicDriversApp["pastAddress"] = pastaddress.SelectedValue;
DicDriversApp["previousAddress"] = previousaddress.Text;
DicDriversApp["previousCity"] = previouscity.Text;
DicDriversApp["previousZip"] = previouszip.Text;
DicDriversApp["previousState"] = previousstate.Text;
DicDriversApp["previousDuration"] = previousduration.Text;
DicDriversApp["previousAddress1"] = previousaddress1.Text;
DicDriversApp["previousCity1"] = previouscity1.Text;
DicDriversApp["previousZip1"] = previouszip1.Text;
DicDriversApp["previousState1"] = previousstate1.Text;
DicDriversApp["previousDuration1"] = previousduration1.Text;
Session["DriversApp"] = DicDriversApp;
}
private void LoadScreenFromMemory(Dictionary<string, string> DicDriversApp)
{
position.Text = DicDriversApp["position"];
fname.Text = DicDriversApp["fname"] ;
middleinitial.Text = DicDriversApp["middleinitial"];
lname.Text = DicDriversApp["lname"];
birthday.Text = DicDriversApp["birthday"];
proofofage.SelectedValue = DicDriversApp["proofofage"];
address.Text = DicDriversApp["address"];
city.Text = DicDriversApp["city"];
state.Text = DicDriversApp["state"];
email.Text = DicDriversApp["email"];
phone.Text = DicDriversApp["phone"];
altphone.Text = DicDriversApp["altphone"];
citizen.SelectedValue = DicDriversApp["citizen"];
whoreferred.Text = DicDriversApp["whoreferred"];
famfriend.Text = DicDriversApp["famfriend"];
relationship.Text = DicDriversApp["relationship"];
rateofpayexpected.Text = DicDriversApp["rateofpayexpected"];
RadioButtonList1.SelectedValue = DicDriversApp["rateofpaytype"];
employednow.SelectedValue = DicDriversApp["employedNow"];
curremployment.Text = DicDriversApp["curremployment"];
pastaddress.SelectedValue = DicDriversApp["pastAddress"];
previousaddress.Text = DicDriversApp["previousAddress"];
previouscity.Text = DicDriversApp["previousCity"];
previouszip.Text = DicDriversApp["previousZip"];
previousstate.Text = DicDriversApp["previousState"];
previousduration.Text = DicDriversApp["previousDuration"];
previousaddress1.Text = DicDriversApp["previousAddress1"];
previouscity1.Text = DicDriversApp["previousCity1"];
previouszip1.Text = DicDriversApp["previousZip1"];
previousstate1.Text = DicDriversApp["previousState1"];
previousduration1.Text = DicDriversApp["previousDuration1"];
}
try something like this:
private void LoadMemoryFromScreen()
{
Dictionary<string, string> driver = new Dictionary<string, string>();
driver.Add("position", position.Text);
driver.Add("othervalue",value.Text); ///etc..
Session["dict"] = driver;
}
then, later on if you want to access the values in your dictionary, use something like this:
var dict = (Dictionary<string, string>)Session["dict"];
problem with this is that you're going to have to use dict.GetElementAt(index) in order to retrieve values, and i don't think that's a very good approach.
This will work, but i kinda dont understand why you are using a dictionary to do this. I assume you are only loading data from 1 person on your page? Then you might as well just make a class with all the properties in it, and then you can just pass that around instead of using this dictionary/session hack.
public class DriversApplicationData
{
public string position {get;set;}
public string firstname {get;set;}
//etc
}
then, you can just do something like
DriversApplicationData data = new DriversApplicationData();
data.position = position.Text;
data.firstname = fname.Text;
this is gonna be alot easier to maintain and to retrieve/insert values.

Categories