How to make a multidimensional Hashtable - c#

I have this data and I need to make an object out of it so I can easily read/write to this object.
I tried to make a dictionary and fill it with hashtables but it is very hard to maintain and I don't even know how to modify the data inside the hashtable inside that dictionary.
this is my bad practice:
Dictionary<string,Hashtable> DICTFormsControls = new Dictionary<string,Hashtable>();
DICTFormsControls[parentfrm] = new Hashtable();
DICTFormsControls[parentfrm][controlid] = new FormControl(controlnm,parentfrm,controlid,controlpermission);
offcourse the "FormControl" is just a simple class to hold the control proberties.
I need to make it so I can get the data easily and modify it just as easy.

A dictionary already contains a hash table for the key. Try something like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DICTFormsControls dictFormcontrols = new DICTFormsControls();
dictFormcontrols.Add(controlnm,parentfrm,controlid,controlpermission)
}
}
public class DICTFormsControls
{
public static Dictionary<int, DICTFormsControls> dict = new Dictionary<int, DICTFormsControls>();
public string controlnm { get; set;}
public string parentfrm { get; set;}
public int controlid { get; set;}
public bool controlpermission {get;set;}
public void Add(string controln, string parentfrm, int controlid, bool controlpermission)
{
dict.Add(controlid, new DICTFormsControls() { controlnm = controlnm, parentfrm = parentfrm, controlid = controlid, controlpermission = controlpermission });
}
}
}
​

Related

ElasticSearch: How to fetch data from fields using ElasticClient from Nest 7.11?

I am using ElasticClient.Search function to get the values of the fields.
The issue is :
The code that i make below make the mapping correctly but for searching it returns null values of the fields that was mapped before.
Main.cs
using Nest;
using System;
using System.Linq;
using System.Threading;
namespace DataAccessConsole
{
class Program
{
public static Uri node;
public static ConnectionSettings settings;
public static ElasticClient client;
static void Main(string[] args)
{
{
node = new Uri("http://localhost:9200");
settings = new ConnectionSettings(node).DefaultIndex("getallcommissionspermanentes");
settings.DefaultFieldNameInferrer(p => p);
client = new ElasticClient(settings);
var indexSettings = new IndexSettings();
indexSettings.NumberOfReplicas = 1;
indexSettings.NumberOfShards = 1;
client.Indices.Create("getallcommissionspermanentes", index => index
.Map<GetAllCommissionsPermanentes>(
x => x
.AutoMap<GetAllCommissionsPermanentes>()
));
client.Search<GetAllCommissionsPermanentes>(s => s
.AllIndices()
);
}
}
GetAllCommissionsPermanentes.cs
the table is located in an edmx model of Entityframework and Data came from SQL SERVER Database
public partial class GetAllCommissionsPermanentes
{
public int ID { get; set; }
public string NomAr { get; set; }
public string NomFr { get; set; }
}
if you need more informations just make a comment below.
Thanks
Code is correct but '.All Indices ()' searches in all indexes, results that do not match the model are coming. This code will return more accurate results;
client.Search<GetAllCommissionsPermanentes>(s => s.Index("getallcommissionspermanentes");

Calling a method that expects an array of objects

I'm learning C# and have written a console program to save an an array of high scores to a file. Although the program works, how I have got it to work is making me feel uneasy and feels more of a hack than a solution so I was looking for guidance on how I should have written it.
What I am currently doing within the Main method is:
Declaring an array of highscore objects
Initialising them
Assigning some values to the array.
I am happy with what I have done up until now, it's the following two steps that make me uneasy
I then declare another HighScore object
I use this object to pass the array of highscores to the SaveHighScores method.
Here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace HighScore
{
class HighScore
{
public string Name { get; set; }
public int Score { get; set; }
public void SaveHighScores(HighScore[] highScores)
{
string allHighScoresText = "";
foreach (HighScore score in highScores)
{
allHighScoresText += $"{score.Name},{score.Score}" + Environment.NewLine;
}
File.WriteAllText("C:/Temp/highscores.csv", allHighScoresText);
}
static void Main(string[] args)
{
HighScore[] highScore = new HighScore[2];
for (int i = 0; i < highScore.Length; i++)
{
highScore[i] = new HighScore();
}
highScore[0].Name = "A";
highScore[0].Score = 100;
highScore[1].Name = "B";
highScore[1].Score = 200;
// are the following two lines correct or am I missing something?
HighScore hs = new HighScore();
hs.SaveHighScores(highScore);
}
}
}
Make SaveHighScores static and you won't need an instance of HighScore to call it. (You can call it directly as HighScore.SaveHighScores())
I prefer to split the representation of your data from the actions that you perform on this data. So I would go for two classes, one for the Data and one for the Save/Load and other business logic
public class HighScore
{
public string Name { get; set; }
public int Score { get; set; }
}
// This class handles the core work to persist your data on the storage medium
// The class is static so you don't need to declare instances and use directly the methods available.
public static class Repo_HighScore
{
// For simplicity, no error Handling but, for a robust implementation,
// error handling is required
public static bool SaveHighScores(HighScore[] highScores)
{
StringBuilder allHighScoresText = new StringBuilder();
foreach (HighScore score in highScores)
allHighScoresText.AppendLine($"{score.Name},{score.Score}");
File.WriteAllText("C:/Temp/highscores.csv", allHighScoresText.ToString());
}
public static HighScore[] LoadHighScores()
{
List<HighScore> hs = new List<HighScore>();
foreach(string line in File.ReadLines("C:/Temp/highscores.csv"))
{
string[] parts = line.Split(',');
HighScore temp = new HighScore()
{ Name = parts[0], Score = Convert.ToInt32(parts[1])};
hs.Add(temp);
}
return hs.ToArray();
}
}

C# Add an element to a each position in a collection object

My goal is to write values to a preexisting .csv file stored in a collection. Currently, I am reading the values stored in the .csv file and storing them in a collection using the filerhelper library. But I want to add 4 column fields {Product ,Base Price,Ship Price,Total Price}, then, if the customer name in my records collection matches the customer name in customerandproducts collection - write in the corresponding data from customerandproducts collection to the 4 fields I added.
Here's a simplified version of my source code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FileHelpers;
namespace ReadFile
{
class Program
{
static void Main()
{
var engine = new FileHelperEngine<Orders>();
var records = engine.ReadFile("Daniel.csv");
// var customersandproducts = addresses.Select(x => new { x.Name, x.AddressLine1, x.AddressLine2, x.City, x.State, x.S_OrderId, x.PostalCode })
// .Join(products, custs => custs.S_OrderId, prod => prod.P_OrderId,(custs, prod) => new { custs.Name, custs.AddressLine1, custs.AddressLine2, custs.City, custs.State, custs.PostalCode, prod.Title, prod.Quantity, prod.ItemPrice, prod.ShippingPrice });
foreach (var record in records)
{
Console.WriteLine(record.Name);
Console.WriteLine(record.Track);
Console.WriteLine(record.Price);
}
}
}
[DelimitedRecord(",")]
public class Orders
{
public string Name;
public string Track;
public string Price;
}
}
Here is the data in my .csv file:
ShipToCompanyorName,PackageTrackingNumber,ShipmentInformationTotalShipmentReferenceCharge
customer1,1Z620Y1V0347293915,12.6
customer2,1Z620Y1V0347106126,9.18
customer3,1Z620Y1V0347584931,13.63
customer4,1Z620Y1V0346366348,11.37
customer5,1Z620Y1V0348472309,31.
customer6,1Z620Y1V0348325290,31.34
My Problem: I want to add {Product ,Base Price,Ship Price,Total Price} into the first row of the .csv file, then fill in each column with information in customerandproducts collection using the customer name as the key.
You can use two classes and later map them with AutoMapper
namespace ReadFile
{
class Program
{
static void Main(string[] args)
{
var engine = new FileHelperEngine<Orders>();
var records = engine.ReadFile("Daniel.csv");
var mapped = Mapper.Map<Orders[], MoreFields[]>(records );
// mapped is an array of the class with more fields
}
}
[DelimitedRecord(",")]
public class Orders
{
public string Name;
public string Track;
public string Price;
}
public class MoreFields: Orders
{
public string Product;
public string BasePrice;
...
}
}
You should use the FieldOptional attribute for your extra fields. Then they will be ignored for import, but included for export.
[DelimitedRecord(",")]
public class Orders
{
public string Name;
public string Track;
public string Price;
[FieldOptional]
public string Product
[FieldOptional]
public string BasePrice
[FieldOptional]
public string ShipPrice
[FieldOptional]
public string TotalPrice
}
Then something like:
var engine = new FileHelperEngine<Orders>();
var records = engine.ReadFile("Daniel.csv");
// transform the collection with a foreach loop
foreach(var record in records)
{
var customer = custs.ByName(record.Name);
record.Product = etc...
record.BasePrice = etc...
}
// write out the file including the optional fields.
engine.WriteFile("Daniel_transformed.csv", records);

Writing enumerable to csv file

I'm sure its very straightforward but I am struggling to figure out how to write an array to file using CSVHelper.
I have a class for example
public class Test
{
public Test()
{
data = new float[]{0,1,2,3,4};
}
public float[] data{get;set;}
}
i would like the data to be written with each array value in a separate cell. I have a custom converter below which is instead providing one cell with all the values in it.
What am I doing wrong?
public class DataArrayConverter<T> : ITypeConverter
{
public string ConvertToString(TypeConverterOptions options, object value)
{
var data = (T[])value;
var s = string.Join(",", data);
}
public object ConvertFromString(TypeConverterOptions options, string text)
{
throw new NotImplementedException();
}
public bool CanConvertFrom(Type type)
{
return type == typeof(string);
}
public bool CanConvertTo(Type type)
{
return type == typeof(string);
}
}
To further detail the answer from Josh Close, here what you need to do to write any IEnumerable (including arrays and generic lists) in a recent version (anything above 3.0) of CsvHelper!
Here the class under test:
public class Test
{
public int[] Data { get; set; }
public Test()
{
Data = new int[] { 0, 1, 2, 3, 4 };
}
}
And a method to show how this can be saved:
static void Main()
{
using (var writer = new StreamWriter("db.csv"))
using (var csv = new CsvWriter(writer))
{
var list = new List<Test>
{
new Test()
};
csv.Configuration.HasHeaderRecord = false;
csv.WriteRecords(list);
writer.Flush();
}
}
The important configuration here is csv.Configuration.HasHeaderRecord = false;. Only with this configuration you will be able to see the data in the csv file.
Further details can be found in the related unit test cases from CsvHelper.
In case you are looking for a solution to store properties of type IEnumerable with different amounts of elements, the following example might be of any help:
using CsvHelper;
using CsvHelper.Configuration;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace CsvHelperSpike
{
class Program
{
static void Main(string[] args)
{
using (var writer = new StreamWriter("db.csv"))
using (var csv = new CsvWriter(writer))
{
csv.Configuration.Delimiter = ";";
var list = new List<AnotherTest>
{
new AnotherTest("Before String") { Tags = new List<string> { "One", "Two", "Three" }, After="After String" },
new AnotherTest("This is still before") {After="after again", Tags=new List<string>{ "Six", "seven","eight", "nine"} }
};
csv.Configuration.RegisterClassMap<TestIndexMap>();
csv.WriteRecords(list);
writer.Flush();
}
using(var reader = new StreamReader("db.csv"))
using(var csv = new CsvReader(reader))
{
csv.Configuration.IncludePrivateMembers = true;
csv.Configuration.RegisterClassMap<TestIndexMap>();
var result = csv.GetRecords<AnotherTest>().ToList();
}
}
private class AnotherTest
{
public string Before { get; private set; }
public string After { get; set; }
public List<string> Tags { get; set; }
public AnotherTest() { }
public AnotherTest(string before)
{
this.Before = before;
}
}
private sealed class TestIndexMap : ClassMap<AnotherTest>
{
public TestIndexMap()
{
Map(m => m.Before).Index(0);
Map(m => m.After).Index(1);
Map(m => m.Tags).Index(2);
}
}
}
}
By using the ClassMap it is possible to enable HasHeaderRecord (the default) again. It is important to note here, that this solution will only work, if the collection with different amounts of elements is the last property. Otherwise the collection needs to have a fixed amount of elements and the ClassMap needs to be adapted accordingly.
This example also shows how to handle properties with a private set. For this to work it is important to use the csv.Configuration.IncludePrivateMembers = true; configuration and have a default constructor on your class.
Unfortunately, it doesn't work like that. Since you are returning , in the converter, it will quote the field, as that is a part of a single field.
Currently the only way to accomplish what you want is to write manually, which isn't too horrible.
foreach( var test in list )
{
foreach( var item in test.Data )
{
csvWriter.WriteField( item );
}
csvWriter.NextRecord();
}
Update
Version 3 has support for reading and writing IEnumerable properties.

C# - In debugger, as soon as execution gets to method, attributes set to 0. Then after, they are back

During defineMapCellPositions() and defineMapCellWalls(), map.cols and map.rows change from values such as 4 and 5 to 0, only for the step through of the methods. A step through the debugger confirms this. Why is this?
Any Help Appreciated, thanks!
Whole Map class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
public class Map
{
public Map()
{
}
public int rows { get; set; }
public int cols { get; set; }
public int boardXPos { get; set; }
public int boardYPos { get; set; }
public int squareSize { get; set; }
private List<List<int>> m_cellPositions = new List<List<int>>();
public List<List<int>> cellPositions
{
get
{
return m_cellPositions;
}
set
{
m_cellPositions = value;
}
}
private List<List<int>> m_cellWalls = new List<List<int>>();
public List<List<int>> cellWalls
{
get
{
return m_cellWalls;
}
set
{
m_cellWalls = value;
}
}
}
Start of MapController Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
public class MapController
{
public MapController()
{
}
Map map = new Map();
Method to set map.cellWalls
public void defineCellWallsList()
{
//map.cellWalls.Clear();
for (int row = 0; row < (map.rows * map.cols); row++)
{
map.cellWalls.Add(new List<int> { 0, 0 });
}
}
Method to set map.cellPositions
public void defineCellPositionsList()
{
//map.cellPositions.Clear();
for (int row = 0; row < map.rows; row++)
{
for (int col = 0; col < map.cols; col++)
{
map.cellPositions.Add(new List<int> { col, row });
}
}
}
To expose the instance of Map in your MapController either make it a public field, or put it in a property. example:
public class MapController
{
public MapController()
{
}
//here you make it "public" so it is visible to outside classes
public Map map = new Map();
// the rest of your code for this class...
Then to access that instance (assuming you are holding onto an instance of the controller)
var controller = new MapController();
controller.map.rows = 5; // now you can access that instance of map.
controller.map.rows = 123;
Now, to inject the Map into the controller (meaning that it is newed up somewhere else in your code, and the same instance can then be shared accross multiple classes using similar injection procedures) you would do something like this...
public class MapController
{
//here you make it "private" cause it doesn't need to be public anymore,
//you also don't new it up here, you are passing in a new on during construction.
private Map map;
public MapController(Map map)
{
this.map = map
}
// the rest of your code for this class...
Now in the code where you new up the objects and stuff...
var map = new Map();
var controller = new MapController(map);
map.rows = 5; // now you can access that instance of map.
map.rows = 123;
// and you can easily share that same instance with other classes
var otherClass = new SomeOtherClassThatNeedsTheMap(map);

Categories