Well, i am new to C# and it seems that i got a problem right over here. I know the problem already, but I don't know how to solve it. I am simply overwriting the object i want to add to my list. Can anyone help me?
List<string> dataSet = new List<string>();
string s;
while ((s = sr.ReadLine()) != null)
{
if (!String.IsNullOrEmpty(s))
{
if (s[0] == '$')
{
dataSet.Add(s);
if (s.Contains("GPGGA"))
{
myData.Add(new DataSet(dataSet));
dataSet.Clear();
Console.WriteLine();
}
}
}
}
If I'm understanding your problem correctly your adding a list of strings to a dataset. You are then clearing that list. It looks to me that your adding a reference to a list, then your calling clear on that list. That is why your loosing your values. You need to add a copy of that list to the other dataset. Try the code below
List<string> dataSet = new List<string>();
string s;
while ((s = sr.ReadLine()) != null)
{
if (!String.IsNullOrEmpty(s))
{
if (s[0] == '$')
{
dataSet.Add(s);
if (s.Contains("GPGGA"))
{
myData.Add(new DataSet(dataSet.ToList()));
dataSet.Clear();
Console.WriteLine();
}
}
}
}
dataSet.ToList() will return a copy of the List instead of adding a reference to it, that way dataSet.Clear() won't clear the list you added to myData
I think one of the problems you may be having is that you've confused yourself a little by naming your List<T> a keyword. A DataSet is its own thing and makes this code very hard to read. First, let's clean that up:
List<string> theData = new List<string>();
string s;
while ((s = sr.ReadLine()) != null)
{
if (!String.IsNullOrEmpty(s))
{
if (s[0] == '$')
{
theData.Add(s);
if (s.Contains("GPGGA"))
{
myData.Add(new DataSet(theData)); //you're passing your source by reference.
theData.Clear();
Console.WriteLine();
}
}
}
}
You need to pass the value of your datasource, but a List<T> is a reference type.
List<string> theData = new List<string>();
string s;
while ((s = sr.ReadLine()) != null)
{
if (!String.IsNullOrEmpty(s))
{
if (s[0] == '$')
{
theData.Add(s);
if (s.Contains("GPGGA"))
{
List<string> bindingdata = theData.ToList();
myData.Add(new DataSet(bindingData)); //you're passing
//your source by value, because it's using a new list.
theData.Clear(); //you can now safely do this.
Console.WriteLine();
}
}
}
}
All of that done, it still won't work, because DataSet doesn't have a constructor that accepts a List<string>. You need to change myData.Add(new DataSet(theData)) to the actual constructor. Interestingly, your DataSet may be the poor choice for what you're doing here. Unless you are using multiple tables, which you don't appear to be, you're better off using just one DataTable.
List<string> theData = new List<string>();
string s;
while ((s = sr.ReadLine()) != null)
{
if (!String.IsNullOrEmpty(s))
{
if (s[0] == '$')
{
theData.Add(s);
if (s.Contains("GPGGA"))
{ //we don't need this now.
//List<string> bindingdata = theData.ToList();
//make myData a DataSet so you can use datatables
// instead of attempting IEnumerable<DataSet>
DataTable foo = new DataTable("Foo");
foreach(string s in theData)
{
var y = foo.NewRow();
y[0] = s;
foo.Rows.Add(y);
}
myData.Add(foo);
theData.Clear(); //you can now safely do this.
Console.WriteLine();
}
}
}
}
Even with all of that, you'd be saving yourself a lot of trouble if you look into the DataTable and StringBuilder classes. There are better ways to do all of this than you're attempting.
Related
As I know string are immutable in C# unless StringBuilder class is used. The situation is, I have an ObjectResult(which implements IEnumerable) of string and I want to convert it to one single string object. There are two options here:
using string.Concat
var myDesiredData = string.Concat(TheObjectResult)
using StringBuilder
var sb = new StringBuiler();
foreach (var item in TheObjectResult)
{
sb.Append(item);
}
var myDesiredData = sb.ToString();
I'm not sure how the first option is working.
Both options are almost identical. This is how string.Concat(IEnumerable<string>) is implemented:
[ComVisible(false)]
public static String Concat(IEnumerable<String> values) {
if (values == null)
throw new ArgumentNullException("values");
Contract.Ensures(Contract.Result<String>() != null);
Contract.EndContractBlock();
StringBuilder result = StringBuilderCache.Acquire();
using(IEnumerator<String> en = values.GetEnumerator()) {
while (en.MoveNext()) {
if (en.Current != null) {
result.Append(en.Current);
}
}
}
return StringBuilderCache.GetStringAndRelease(result);
}
I would go with string.Concat, because why write a method that already exists.
I need help with my code as I can't seem to find the culprit of why adding type <T> to a list many times overwrites the other values being added.
Below is my code:
public IEnumerable<T> Query<T>(string query, object parameters = null) where T : new()
{
var lists = new List<T>();
var ObjType = new T();
var ObjProps = ObjType.GetType().GetProperties();
int Objlen = ObjProps.Length;
if (parameters == null)
{
DBConnection.Open();
using (MySqlTransaction mysqlTransaction = DBConnection.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
{
try
{
using (MySqlCommand command = new MySqlCommand(query, DBConnection))
{
command.Transaction = mysqlTransaction;
using (MySqlDataReader dataReader = command.ExecuteReader())
{
if (dataReader.HasRows)
{
while (dataReader.Read())
{
for (int i = 0; i < dataReader.FieldCount; i++)
{
var dataValue = dataReader.GetValue(i);
ObjProps.FirstOrDefault(p => p.Name == dataReader.GetName(i)).SetValue(ObjType, dataValue);
}
lists.Add(ObjType);
}
}
}
}
}
catch (Exception)
{
mysqlTransaction.Rollback();
DBConnection.Close();
throw;
}
finally
{
if (DBConnection != null)
{
DBConnection.Close();
}
}
}
}
return lists;
}
I can't seem to find the logic error in my code. As I execute the code, the first add to lists are okay.
But as soon as it iterates again for the for loop, the values seemed to be overwritten and I don't even have a clue as to why this is happening.
Below is the picture:
Any help/clarification/answer is greatly appreciated.
The line var ObjType = new T(); should be inside the while loop and not at the top. Otherwise you are just modifying the same object and not adding new ones.
You aren't creating a new <T> (ObjType) in your for loop. When you do, don't forget to reset ObjProps to reference the new ObjType.
You get the error because you are always setting the properties of the same instance and adding the same instance to the list.
Add ObjType = new T(); before the for loop.
I'd like to make below code cleaner (in the eye of the beholder).
var lines = new StringReader(lotsOfIncomingLinesWithNewLineCharacters);
var resultingLines = new List<string>();
string line;
while( (line = lines.ReadLine() ) != null )
{
if( line.Substring(0,5) == "value" )
{
resultingLines.Add(line);
}
}
to something like
var resultingLinesQuery =
lotsOfIncomingLinesWithNewLineCharacters
.Where(s=>s.Substring(0,5) == "value );
Hopefully I have illustrated that I'd prefer to not have the result as a list (to not fill up memory) and that StringReader is not mandatory.
There is the naïve solution to create an extension and move the ReadLine there but I have a feeling there might be a better way.
Basically you need a way of extracting lines from a TextReader. Here's a simple solution which will only iterate once:
public static IEnumerable<string> ReadLines(this TextReader reader)
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
You could use that with:
var resultingLinesQuery =
new StringReader(lotsOfIncomingLinesWithNewLineCharacters)
.ReadLines()
.Where(s => s.Substring(0,5) == "value");
But ideally, you should be able to iterate over an IEnumerable<T> more than once. If you only need this for strings, you could use:
public static IEnumerable<string> SplitIntoLines(this string text)
{
using (var reader = new StringReader(text))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
Then:
var resultingLinesQuery =
lotsOfIncomingLinesWithNewLineCharacters
.SplitIntoLines()
.Where(s => s.Substring(0,5) == "value");
I want to add new properties to an object based on loop iterations, is this possible in .Net? The reason I want to do this is I am looping through rows in an excel spreadsheet and for every successfully read row I want to create a new dynamic object property. So when the loop is complete I can simply pass the object to a method and log all the records.
See below for code so far:
protected void ReadData(string filePath, bool upload)
{
StringBuilder sb = new StringBuilder();
#region upload
if (upload == true) // CSV file upload chosen
{
using (CsvReader csv = new CsvReader(new StreamReader(filePath), true)) // Cache CSV file to memory
{
int fieldCount = csv.FieldCount; // Total number of fields per row
string[] headers = csv.GetFieldHeaders(); // Correct CSV headers stored in array
SortedList<int, string> errorList = new SortedList<int, string>(); // This list will contain error values
ORCData data = new ORCData();
bool errorFlag = false;
int errorCount = 0;
// Check if headers are correct first before reading data
if (headers[0] != "first name" || headers[1] != "last name" || headers[2] != "job title" || headers[3] != "email address" || headers[4] != "telephone number" || headers[5] != "company" || headers[6] != "research manager" || headers[7] != "user card number")
{
sb.Append("Headers are incorrect");
}
else
{
while (csv.ReadNextRecord())
try
{
//Check csv obj data for valid values
for (int i = 0; i < fieldCount; i++)
{
if (i == 0 || i == 1) // FirstName and LastName
{
if (Regex.IsMatch(csv[i].ToString(), "^[a-z]+$", RegexOptions.IgnoreCase) == false) //REGEX letters only min of 5 char max of 20
{
errorList.Add(errorCount, csv[i]);
errorCount += 1;
errorFlag = true;
string text = csv[i].ToString();
}
}
}
if (errorFlag == true)
{
sb.Append("<b>" + "Number of Error: " + errorCount + "</b>");
sb.Append("<ul>");
foreach (KeyValuePair<int, string> key in errorList)
{
sb.Append("<li>" + key.Value + "</li>");
}
}
else // All validation checks equaled to false. Create User
{
string message = ORCLdap.CreateUserAccount(rootLDAPPath, svcUsername, svcPassword, csv[0], csv[1], csv[2], csv[3], csv[4], csv[5], csv[7]);
// TODO: Add to object here
sb.Append(message);
//sb.Append("<b>New user data uploaded successfully</b>");
}
}// end of try
catch (Exception ex)
{
sb.Append(ex.ToString());
}
finally
{
lblMessage.Text = sb.ToString();
sb.Remove(0, sb.Length);
hdnRdoSelection.Value = "1";
}
}
}
}
#endregion
I have never tried to do this before so I am not sure how I would approach it but any help would be great. Thanks.
I want to add new properties to an object based on loop iterations, is this possible in .Net?
Sort of. You probably want to use ExpandoObject, treating it as an IDictionary<string, object> when you're adding the properties.
Having said that, if you're not going to try to use those properties as properties later, do you actually need them to be properties at all? Why not just use a Dictionary<string, object> to start with?
Yes, you could use ExpandoObject for this. Simply assign the properties you want and it will assume those properties.
dynamic settings= new ExpandoObject();
This program is meant to read in a csv file and create a dictionary from it, which is then used to translate a word typed into a textbox (txtINPUT) and output the result to another textbox (txtOutput).
The program doesnt translate anything and always outputs "No translation found."
I've never used the dictionary class before so I dont know where the problem is coming from.
Thanks for any help you can give me.
Dictionary<string, string> dictionary;
private void CreateDictionary()
{
//Load file
List<string> list = new List<string>();
using (StreamReader reader = new StreamReader("dictionarylist.csv"))
{
string line;
while ((line = reader.ReadLine()) != null)
{
//Add to dictionary
dictionary = new Dictionary<string, string>();
string[] split = line.Split(',');
dictionary.Add(split[0], split[1]);
}
}
}
private void btnTranslate_Click(object sender, EventArgs e)
{
CreateDictionary();
string outputString = null;
if (dictionary.TryGetValue(txtInput.Text, out outputString))
{
txtOutput.Text = outputString;
}
else
{
txtOutput.Text = ("No translation found");
}
}
You are creating a new instance of a Dictionary each loop cycle, basically overwriting it each time you read a line. Move this line out of the loop:
// Instantiate a dictionary
var map = new Dictionary<string, string>();
Also why not load dictionary one time, you are loading it each button click, this is not efficient.
(>=.NET 3) The same using LINQ ToDictionary():
usign System.Linq;
var map = File.ReadAllLines()
.Select(l =>
{
var pair = l.Split(',');
return new { First = pair[0], Second = pair[1] }
})
.ToDictionary(k => k.First, v => v.Second);
In your while loop, you create a new dictionary every single pass!
You want to create one dictionary, and add all the entries to that:
while ((line = reader.ReadLine()) != null)
{
//Add to dictionary
dictionary = new Dictionary<string, string>(); /* DON'T CREATE NEW DICTIONARIES */
string[] split = line.Split(',');
dictionary.Add(split[0], split[1]);
}
You should do it more like this:
List<string> list = new List<string>();
dictionary = new Dictionary<string, string>(); /* CREATE ONE DICTIONARY */
using (StreamReader reader = new StreamReader("dictionarylist.csv"))
{
string line;
while ((line = reader.ReadLine()) != null)
{
string[] split = line.Split(',');
dictionary.Add(split[0], split[1]);
}
}