Class List Keeps Printing Out As Class Name In Console? - c#

Ok, so maybe I'm just tired or something but I can't seem to figure out why this keeps happening.
The code below is called every day for a data point in a database I have.
When I print to the console for debugging, it simply prints out as:
NamespaceName.SharePrices
Not sure what is going on.
public void OnData(TradeBars data)
{
decimal price = data["IBM"].Price;
DateTime today = data["IBM"].Time;
//--------------Below works fine.
if (today.Date >= nextTradeDate.Date)
{
MarketOnOpenOrder("IBM", 50);
Debug("Purchased Stock");
nextTradeDate = today.AddDays(1);
MarketOnOpenOrder("IBM", -25);
}
var derpList = new SharePrices { theDate = today, sharePrice = price };
List<SharePrices> newList = new List<SharePrices>();
newList.Add(derpList);
newList.ForEach(Console.WriteLine);
}
}
public class SharePrices
{
public DateTime theDate { get; set; }
public decimal sharePrice { get; set; }
}
Please excuse my naming conventions. This is just a wireframe for a personal project.
//----------Edit
Thanks for the help guys. I guess what I wasn't understanding is why it was working in my TestClass I wrote just playing with fake data, and when the real implementation came it didn't work:
public static void FindWindowDays()
{
DateTime currentDate = DateTime.Now;
var dates = new List<DateTime>();
for (var dt = currentDate.AddDays(-windowDays); dt <= currentDate; dt = dt.AddDays(1))
{
dates.Add(dt);
}
var ascending = dates.OrderByDescending(i => i);
foreach (var datesyo in ascending)
{
Console.WriteLine(datesyo);
}
}
This seemed to work fine printing the DateTime to console without converting to string. But when I added the second element, it stopped working. That's where I got confuddled.

C# doesn't know anything about the SharePrices other than the class name. If you want it to display something specific, you will need to override the ToString() method like so:
public override string ToString()
{
return "SharePrice: " + theDate.ToString() + ": " + sharePrice.ToString();
}
Of course, you can format it however you like, that is the beauty of it. If you only care about the price and not the date, only return the sharePrice.

You should override ToString() for your class in format as you want, for example like this:
public class SharePrices
{
public DateTime theDate { get; set; }
public decimal sharePrice { get; set; }
public override string ToString()
{
return String.Format("The Date: {0}; Share Price: {1};", theDate, sharePrice);
}
}
By default, without overriding, ToString() returns a string that represents the current object. So that's why you get what you described.

When you call Console.WriteLine on a class, it will call the ToString() method on that class automatically.
If you want to print the details out, you will over need to override ToString() in your class, or call Console.WriteLine with each property you want to print out.

this will work without having to use .ToString()
public class SharePrices
{
public DateTime theDate { get; set; }
public decimal sharePrice { get; set; }
}
SharePrices sp = new SharePrices() { theDate = DateTime.Now, sharePrice = 10 };
var newList2 = new List<SharePrices>();
newList2.Add(sp);
newList2.ForEach(itemX => Console.WriteLine("Date: {0} Sharprice: {1}",sp.theDate, sp.sharePrice));

Related

String '22-05-1998' was not recognized as a valid DateTime

I am using CsvHelper library to read the data from a CSV file looks like
this
My code:
public class CsvTransaction
{
[Name("Account")]
public string Account { get; set; }
[Name("Amount")]
public int Amount { get; set; }
[Name("Date")]
public DateTime Date { get; set; }
[Name("Note")]
public string Note { get; set; }
}
public void call()
{
using (var StreamReader = new StreamReader(#"C:\Users\santo\Downloads\industry.csv"))
{
using (var csvReader = new CsvReader(StreamReader, CultureInfo.InvariantCulture))
{
var records = csvReader.GetRecords<CsvTransaction>().ToList();
Console.WriteLine(records.Count);
foreach(var item in records)
{
Console.WriteLine(item.Amount.GetType());
Console.WriteLine(item.Note.GetType());
CsvAddTransaction(item.Account, item.Amount, item.Date, item.Note);
}
}
}
}
when I call this call(), it is saying String '22-05-1998' was not recognized as a valid DateTime. all the other are giving exact datatypes I needed, but there is a problem with item.Date
Can anyone help me with this?
You have to define DateTime format, you are getting this error because parsing mechanism might be expecting something like "MM-dd-yyyy" and instead of that, it receives "dd-MM-yyyy".
Here's documentation which describes DateTime formatting in detail.
And here is url to potential solution to your problem.

Sorting a ListBox in c# with multiple fields

Is there a way to sort a list box on one field then another?
(I saw the other posts but I think this is a bit more involved). I could do this the long way but thought there was a faster shorthand version I just wasn't aware of.
Basically this reads a directory for all the folders in it with the format of:
DATENAME
I parse out the name from the date. I need to organize these by name THEN by date (the second filter is what is tripping me up).
So a folder of:
12012016TULLY
1202019LAVA
2202018LAVA
5162019CLOUD
5202020LAVA
would look like
5162019CLOUD
2202018LAVA
1202019LAVA
5202020LAVA
12012016TULLY
So this is what I have:
class MyListBoxItem
{
public string StudyBaseFolder { get; set; }
public string StudyName { get; set; }
public string UserLastName { get; set; }
public string StudyDate { get; set; }
}
List<MyListBoxItem> studiesAndFolders = new List<MyListBoxItem>();
//later int he code i build a list of studyNames (which is a path and I pasre the path here too)
foreach (string sn in studyName)
{
//get user name
String lastName = getLastName(sn);
String theDate = getDate(sn);
//can I organize this based on the LAST NAME THEN THE DATE
studiesAndFolders.Add(new MyListBoxItem { StudyBaseFolder = path, StudyName = sn, UserLastName = lastName, StudyDate = theDate });
}
Then I finally add this to the listbox.
listDirectories.Items.Clear();
//I do it this way so a double click on an item gets the object back and I can do things with it.
foreach(MyListBoxItem direc in studiesAndFolders)
{
listDirectories.Items.Add(direc);
}
listbox.sorted=true didn't help, and I am sure there might be an expression (LINQ to the rescue?). I was just going to do it the long way with a ton of cases when I take the studiesAndFolders and put it to the list.
This code sorts by name, then by date. And should be easy to read.
foreach(MyListBoxItem direc in studiesAndFolders.OrderBy(x => x.StudyName).ThenBy(x => x.StudyDate))
{
listDirectories.Items.Add(direc);
}
As others have noted, you should be storing the StudyDate as a DateTime unless you want it sorted alphabetically.
Firstly, change type of StudyDate to DateTime
class MyListBoxItem
{
...
public DateTime StudyDate { get; set; }
}
After, create new comparer
public class MyListBoxItemComparer : IComparer<MyListBoxItem>
{
public int Compare(MyListBoxItem x, MyListBoxItem y)
{
if (x.StudyName == y.StudyName)
{
return x.StudyDate.CompareTo(y.StudyDate);
}
return String.Compare(x.StudyName, y.StudyName, StringComparison.Ordinal);
}
}
Finally, use SortedSet instead of List
SortedSet<MyListBoxItem> studiesAndFolders = new SortedSet<MyListBoxItem>(new MyListBoxItemComparer());
For ordering based on the date correctly you need StudyDate to be of type DateTime
class MyListBoxItem
{
public string StudyBaseFolder { get; set; }
public string StudyName { get; set; }
public string UserLastName { get; set; }
public DateTime StudyDate { get; set; }
}
Then you can order by using LINQ extension methods.
var orderedDirectories =
directories.OrderBy(dir => dir.StudyName)
.ThenBy(dir => dir.StudyDate);
foreach (var directory in orderedDirectories)
{
listBox.Items.Add(directory);
}
You can override .ToString() method in MyListBoxItem class that listbox will display items as you want.
class MyListBoxItem
{
public string StudyBaseFolder { get; set; }
public string StudyName { get; set; }
public string UserLastName { get; set; }
public DateTime StudyDate { get; set; }
public override string ToString()
{
return $"{StudyDate:MMddyyyy}{StudyName}";
}
}
If you can use LINQ in your project, first you should make StudyDate type of DateTime. Then you could do this:
MyList.OrderBy(x => x.StudyName).ThenByDescending(x=>x.StudyDate).ToList()

Calculate years in a POCO Calculated Property

I'm assuming I'm pretty close. I have a value StartedAgent that will contain a specific date entered by the user. Lets say they entered "1/1/1985" I then want to create a calculated property that I can use to display how many years since this agent first started working in Real Estate. Below is my class. I have tried to take a stab at it, but I'm coming up short. I'm using MVC 5, EF 6 & .Net 4.5 in the flavor of C#.
namespace OrlandoAppraiser.Models
{
public class Appraiser
{
public int AgentID { get; set; }
public string Name { get; set; }
public string LicenseNum { get; set; }
public DateTime StartedAgent { get; set; }
public string YearsAsAgent
{
get { return (Math.Floor((DateTime.Now - StartedRealEstate).TotalDays / 365.25D)); }
}
}
}
I have looked at some different answers, but I'm having trouble finding a way of doing this simple inside a calculated property. I know it shouldn't be that much different, but I'm getting errors with my code.
This is a pretty simplistic approach. Make sure you call ToString() if the property is a string.
public string YearsAsAgent
{
get { return (DateTime.Now.Year - StartedRealEstate.Year).ToString(); }
}
This should help. Modified version of this.
DateTime _startedRealEstate = new DateTime(2012, 11, 15);
public DateTime StartedRealEstate { get { return _startedRealEstate; } set { _startedRealEstate = value; } }
public int YearsAsAgent
{
get
{
DateTime zeroTime = new DateTime(1, 1, 1);
TimeSpan span = DateTime.Now - StartedRealEstate;
int years = (zeroTime + span).Year - 1;
return years;
}
}
private void button1_Click_2(object sender, EventArgs e)
{
int totalYears = YearsAsAgent;
}

Setting variable types from CSV

var csv =
from line in File.ReadAllLines("C:/file.csv")
let customerRecord = line.Split(',')
select new Customer()
{
contactID = customerRecord[0],
surveyDate = customerRecord[1],
project = customerRecord[2],
projectCode = customerRecord[3]
};
public class Customer
{
public string contactID { get; set; }
public string surveyDate { get; set; }
public string project { get; set; }
public string projectCode { get; set; }
}
I'd like to be able to read the surveyDate as a DateTime in order to compare it with other DateTime fields I'm joining to the csv file.
I've tried just setting surveyDate as Date.Time in the class, and I've tried converting it in the select statement, but both fail with the following error:
FormatException: The string was not recognized as a valid DateTime. There is an unknown word starting at index 0.
I do have to work with the csv file, so I can't add the data to sql server.
contactID,responseDate,project,projectID
1,6/4/2009,0-3 months,1
2,6/11/2009,0-3 months,1
You need to parse it when reading as well as changing the type. I'm not sure how you tried it in the first place. Also, use DateTime.ParseExact if you know the format.
var csv =
from line in File.ReadAllLines("C:/file.csv")
let customerRecord = line.Split(',')
select new Customer()
{
contactID = customerRecord[0],
surveyDate = DateTime.Parse(customerRecord[1]),
project = customerRecord[2],
projectCode = customerRecord[3]
};
public class Customer
{
public string contactID { get; set; }
public DateTime surveyDate { get; set; }
public string project { get; set; }
public string projectCode { get; set; }
}
Judging by the error you just posted, I think it's probably double-quoted. Try trimming the quotes:
DateTime.Parse(customerRecord[1].Trim('"'))
Right... Because you can never know what the input will be from the CSV you can't always try and implicitly convert the string to a DateTime and because you want to do the convert of a string within the select a way to do this is an extension method.
public static class StringExtensions
{
public static DateTime TryParseDate(this string strToParse)
{
DateTime dt = new DateTime();
DateTime.TryParse(strToParse, out dt);
return dt;
}
}
Then when you want to convert in the select do it like this:
var csv = from line in File.ReadAllLines("C:/file.csv")
let customerRecord = line.Split(',')
select new Customer()
{
contactID = customerRecord[0],
surveyDate = customerRecord[1].TryParseDate(),
project = customerRecord[2],
projectCode = customerRecord[3]
};
You have your own method. Hope this helps and works for you.
The string you want to parse will be passed to the method and then you can handle it and return a valid date time, handling incorrect inputs.
http://msdn.microsoft.com/en-us/library/bb383977.aspx
See this link for an explanation
After changing Customer so that SurveyDate is a DateTime then:
select new Customer()
{
contactID = customerRecord[0],
surveyDate = DateTime.Parse(customerRecord[1]),
project = customerRecord[2],
projectCode = customerRecord[3]
};
You may need to use forms of Parse or ParseExact that take a format string, to be sure of the correct result. That format string depends on the format used in the file.
Alternatively, you could create a Parse static method on Customer:
public class Customer
{
public string contactID { get; set; }
public DateTime surveyDate { get; set; }
public string project { get; set; }
public string projectCode { get; set; }
public static Customer Parse(string line)
{
var parts = line.Split(',');
return new Customer{
contactID = parts[0],
surveyDate = DateTime.Parse(customerRecord[1]),
project = customerRecord[2],
projectCode = customerRecord[3]
};
};
Then:
var csv =
from line in File.ReadLines("C:/file.csv")
select Customer.Parse(line);
This has an advantage if obtaining a Customer from such a formatted string happens more than once in your code. It needlessly fills Customer with cruft if this is the only place you do it. Note I favour ReadLines over ReadAllLines to get a line at a time rather than read the whole thing before starting do produce customers.
Incidentally, .NET conventions favour capitals on property names. SurveyDate rather than surveyDate etc.
I've tried just setting surveyDate as Date.Time in the class, and I've tried converting it in the select statement, but both fail.
Well you need to do both. You need to change the property type (ideally fixing the naming at the same time to follow conventions) and change where you're setting it, probably using DateTime.ParseExact, specifying the format and probably the invariant culture.
(I'm assuming you know the format of the date in the file - I would strongly advise you to use DateTime.ParseExact rather than just letting the framework try various formats until it finds one which works.)
EDIT: Now that we've seen the file, it looks like you'd want either
DateTime.ParseExact(text, "d/M/yyyy", CultureInfo.InvariantCulture)
or:
DateTime.ParseExact(text, "M/d/yyyy", CultureInfo.InvariantCulture)
... but we can't tell which, as we don't know whether "6/4/2009" means April 6th or June 4th.
You should convert your customerRecord[1] string to a DateTime.
var csv =
from line in File.ReadAllLines("C:/file.csv")
let customerRecord = line.Split(',')
select new Customer()
{
contactID = customerRecord[0],
surveyDate = DateTime.Parse(customerRecord[1]),
project = customerRecord[2],
projectCode = customerRecord[3]
};
public class Customer
{
public string contactID { get; set; }
public DateTime surveyDate { get; set; }
public string project { get; set; }
public string projectCode { get; set; }
}

LINQ - Set element in Dictionary to empty where DateTime value is oldest

I have a Dictionary<string, XMLMessage> where XMLMessage is a struct:
private struct XMLMessage
{
public string Message { get; set; }
public DateTime TimeRead { get; set; }
}
I will use the Dictionary similar to this:
storedMessages["1X"] = new XMLMessage() { Message = "<XML>1X</XML>", TimeRead = DateTime.Now };
storedMessages["1Y"] = new XMLMessage() { Message = "<XML>1Y</XML>", TimeRead = DateTime.Now };
There will be a gap in seconds between the the dictionary object assigning a value hence the DateTime object.
At some point I need to keep the keys in the Dictionary but the oldest value to be set to empty.
I have tried this but don't seem to have got it quite right.
storedMessages.Where(x => x.Key.Contains("1")).OrderBy(s => s.Value.TimeRead).Skip(1)
Thanks
UPDATE: I think I can do something like this but wanted to get your opinions
var j = storedMessages.Where(x => x.Key.Contains("1")).OrderByDescending(s => s.Value.TimeRead).First().Key;
storedMessages[j] = new XMLMessage();
Yes, your updated version looks okay - although I'd say you'd be better off storing a list in time order as well as the dictionary, to make life easier.
I would strongly discourage you from using mutable structs though. Either use a class, or change the struct to be immutable.
Example of making it a class:
private class XmlMessage
{
public string Message { get; set; }
public DateTime TimeRead { get; set; }
}
Example of making it an immutable struct:
private struct XmlMessage
{
private readonly string message;
private readonly DateTime timeRead;
public string Message { get { return message; } }
public DateTime TimeRead { get { return timeRead; } }
public XmlMessage(string message, DateTime timeRead)
{
this.message = message;
this.timeRead = timeRead;
}
}
Of course you could make it an immutable class instead...

Categories

Resources