Return false if type properties equals null or 0 - c#

I tried following the method as follows here: Checking if Object has null in every property . However, when instantiating Order newOrder = new Order();. I cannot simple just implement bool props = newOrder.ArePropertiesNotNull(). What am I supposed to add to my Order class? And where do I implement the function for ArePropertiesNotNull<T>(this T obj)? I would like to know if there is a way to return false if value returned equals 0 or null?
Here is my code:
OrderProdRepository.cs
...
public bool ReadFromFile(string _date)
{
taxesFile.ReadFile();
productsFile.ReadFile();
string orderFileName = $"C:\\tempfolder\\Orders_{_date}.txt";
List<string> lines = File.ReadAllLines(orderFileName).ToList();
foreach (var line in lines.Skip(1)) //?? new List<string>(0)
{
List<string> entry = line.Split(',').ToList();
Order newOrder = new Order();
int.TryParse(entry[0], out int orderNumber);
newOrder.OrderNumber = orderNumber;
newOrder.Date = _date;
newOrder.CustomerName = entry[1];
newOrder.State = taxesFile.StateAbbreviation(entry[2]);
newOrder.StateName = taxesFile.StateName(newOrder.State);
decimal.TryParse(entry[3], out decimal taxRate);
newOrder.TaxRate = taxesFile.TaxRate(taxRate);
newOrder.ProductType = productsFile.ProductType(entry[4]);
decimal.TryParse(entry[5], out decimal area);
newOrder.Area = area;
decimal.TryParse(entry[6], out decimal costPerSquareFoot);
newOrder.CostPerSquareFoot = productsFile.CostPerSquareFoot(costPerSquareFoot);
decimal.TryParse(entry[7], out decimal laborCostPerSquareFoot);
newOrder.LaborCostPerSquareFoot = productsFile.LaborCostPerSquareFoot(laborCostPerSquareFoot);
decimal.TryParse(entry[8], out decimal materialCost);
newOrder.MaterialCost = materialCost;
decimal.TryParse(entry[9], out decimal laborCost);
newOrder.LaborCost = laborCost;
decimal.TryParse(entry[10], out decimal tax);
newOrder.Tax = tax;
decimal.TryParse(entry[11], out decimal total);
newOrder.Total = total;
orderList.Add(newOrder);
}
return true;
}
...

I think you need a function to check each line for null and/or 0 values:
private bool IsValidLine(string line)
{
if (line == null)
return false;
var arr = line.Split(',');
//Uncomment this if splitting the line will always return 11 items array.
//if (arr.Length < 11)
// return false;
return arr.Aggregate(0, (n, s) =>
(decimal.TryParse(s, out decimal d) && d == 0) ||
string.IsNullOrWhiteSpace(s) ? n + 1 : n) == 0;
}
You can use it in your code as follows:
public bool ReadFromFile(string _date)
{
var orderFileName = $"C:\\tempfolder\\Orders_{_date}.txt";
var lines = File.ReadAllLines(orderFileName);
foreach (var line in lines.Skip(1))
{
//If parsing any line returns false.
if (!IsValidLine(line))
return false;
//Or if you need to create a list of the valid Order entries.
if (IsValidLine(line))
{
var order = new Order();
//...
orderList.Add(newOrder);
}
}
return true;
}
Alternatives:
Add a static function in the Order class to parse a given line and return a new object of Order type if the line is valid. Something like this.
If its not too late, then consider using a local database or serialization. Something like this and maybe this if you don't mind a vb.net example.

You need to create this method an extension method. It should be defined in static class:
public static class ObjectExtensions
{
public static bool ArePropertiesNotNull<T>(this T obj)
{
return typeof(T).GetProperties().All(propertyInfo => propertyInfo.GetValue(obj) != null);
}
}

Related

How to sort C# Datatable with empty column values at the end

I have a C# datatable with 1000's of rows. But primary 200 rows have empty values (multiple columns). Filter would happen to those columns as empty values to occupy as last. I want output will happen with in the table or new table with filter but not as linq rows. Please help me out
Pictures speaks more words, refer this for better understanding:
There are 2 things here that you should consider:
"Empty Value": To sort items that followed by empty value columns you need .OrderBy(s => String.IsNullOrEmpty(s["OrderNo"].ToString()))
"Order No Format": To sort custom order number you need to use IComparer<string>. As you show in your question I assume the format for Order No could be XXXXX or XXXX-XXXX.
So you need to first OrderBy empty values ThenBy your custom IComparer<string> something like this:
public class OrderNoComparer : IComparer<string>
{
public int Compare(string x, string y)
{
int xFirstValue = 0;
int xSecondValue = 0;
int yFirstValue = 0;
int ySecondValue = 0;
if (x.Contains("-"))
{
xFirstValue = Convert.ToInt32(x.Split(new char[] { '-' })[0]);
xSecondValue = Convert.ToInt32(x.Split(new char[] { '-' })[1]);
}
else
{
xFirstValue = Convert.ToInt32(x);
}
if (y.Contains("-"))
{
yFirstValue = Convert.ToInt32(y.Split(new char[] { '-' })[0]);
ySecondValue = Convert.ToInt32(y.Split(new char[] { '-' })[1]);
}
else
{
yFirstValue = Convert.ToInt32(y);
}
if (xFirstValue > yFirstValue)
{
return 1;
}
else if (xFirstValue < yFirstValue)
{
return -1;
}
else //means equal
{
if (xSecondValue > ySecondValue)
{
return 1;
}
else if (xSecondValue == ySecondValue)
{
return 0;
}
else
{
return -1;
}
}
}
}
Full example is here:
DataTable dtOrder = new DataTable();
dtOrder.Columns.Add("OrderNo");
var dr1 = dtOrder.NewRow();
dr1["OrderNo"] = "";
dtOrder.Rows.Add(dr1);
var dr2 = dtOrder.NewRow();
dr2["OrderNo"] = "569-875";
dtOrder.Rows.Add(dr2);
var dr3 = dtOrder.NewRow();
dr3["OrderNo"] = "569975";
dtOrder.Rows.Add(dr3);
var dr4 = dtOrder.NewRow();
dr4["OrderNo"] = "569865";
dtOrder.Rows.Add(dr4);
var dr5 = dtOrder.NewRow();
dr5["OrderNo"] = "569-975";
dtOrder.Rows.Add(dr5);
var dr6 = dtOrder.NewRow();
dr6["OrderNo"] = "569-875";
dtOrder.Rows.Add(dr6);
var result = dtOrder.AsEnumerable().AsQueryable()
.OrderBy(s => String.IsNullOrEmpty(s["OrderNo"].ToString()))
.ThenBy(o => o["OrderNo"].ToString(), new OrderNoComparer())
.ToList();
foreach (var item in result)
{
Console.WriteLine(item["OrderNo"]);
}
Then the output would be like you expected:
569-875
569-875
569-975
569865
569975

Comparing two objects in a List<> and assign them with new value

How do I compare two object in a list? The list contains objects with two properties Number and description. The numbers are such as CC2 and NS1, and the description are Abcd, acd, …
The list's member: CC1 Abcd, NU15 Abcd, CC2 Acd, NS1 Abd, CC21 Abd
string start = "NU15 Abcd";
string end = "NS1 Abd";
string startletters = string.Empty;
string startnumbers = string.Empty;
string endletters = string.Empty;
string endnumbers = string.Empty;
foreach (char c in start)
{
if (Char.IsLetter(c))
{
startletters += c;
}
if (Char.IsNumber(c))
{
startnumbers += c;
}
}
foreach (char c in end)
{
if (Char.IsLetter(c))
{
endletters += c;
}
if (Char.IsNumber(c))
{
endnumbers += c;
}
}
for (int i = 0; i < Program.file.Count; i++)
{
if (startname == Program.file[i].Desc && start != Program.file[i].Number)
{
start = Program.file[i].Number;
}
}
What I want to do is to check if start has another number that start with NS, similarly with end, to check if Abd has another number so that both will match(both are starting with CC). Keep in mind that the value of start and end is in this format but not the same value as i assigned because they are input, the value above are just for reference. So the result will be
start = "CC1 Abcd"; end = "CC21 Abd";
As I understood from your question:
//This will get you the first two characters of the string
string subS = start.Substring(0,2);
string subE = end.Substring(0,2);
//Do the comparison
if (subS == subE)
{
//your logic
}
else
{
//another logic
}

C# reference array assignment issue

I'm having a little trouble reading values in from a database and assigning them to an array. It seem to work in my unit tests, but in practice some values are missing.
Here's my database code:
private void GetParameterValuesFromDatabase()
{
this.parameterValues = (from DataRow r in this.database.RunCommand("select * from KST_PARAM_VALUES v join DM_PARM_NAME p on v.PARM_NAME_KEY = p.PARM_NAME_KEY").Rows
where (int)r["SCENARIO_KEY"] == this.scenario.ScenarioKey
select new DatabaseParameter
{
ParameterValuesKey = r.Field<int>(0),
ProfileType = r.Field<string>(1),
ScenarioKey = r.Field<int>(2),
StressEditorKey = r.Field<int>(3),
StressClassKey = r.Field<int>(4),
PeriodKey = r.Field<int>(5),
ParameterNameKey = r.Field<int>(6),
ParameterValue = r.Field<double>(7),
ActiveStress = (r.Field<string>(8) == "Y") ? true : false,
ParameterKey = (int)r["PARM_NUMBER"]
}).ToDictionary(r => r.ParameterValuesKey, r => r);
}
Not having any issues with this part of my code, just showing for completeness.
private void LoadParameters()
{
this.GetParameterValuesFromDatabase();
// TODO: Assuming 9 periods for now, change to allow for variable periods
for (int i = 1; i <= MaxNumberOfStressPeriods; i++)
{
this.parametersByPeriod.Add(i, this.parameterValues.Where(t => t.Value.PeriodKey == i).ToDictionary(t => t.Key, t => t.Value));
}
Log.Instance.LogMessage(LogLevel.Debug, "Created parameter dictionaries from database");
// For every stress editor in the dictionary of stress editors
foreach (KeyValuePair<int, ClassList> ed in this.stressParams)
{
// For every type of class selector
foreach (ClassSelector c in Enum.GetValues(typeof(ClassSelector)))
{
// For each of the classes within each class list within the editor
for (int i = 0; i < ed.Value.ClassLists[c].Count; i++)
{
string className = ed.Value.ClassLists[c][i].Name;
// For each double array in each class
foreach (KeyValuePair<int, double[]> t in ed.Value.ClassLists[c][i].ClassVariables.EditorParameters)
{
double[] values = this.GetParameterValues(t.Key, ed.Key, className);
BasicStressEditorVariables.AddParameters(values, ed.Value, className, t.Key);
}
}
}
}
}
}
Above shows the overall LoadParameters() method.
Below we have some code that selects 9 values from the dictionary constructed from the database, ready to be added to the array.
private double[] GetParameterValues(int paramKey, int editorKey, string className)
{
double[] values = new double[9];
for (int i = 1; i <= MaxNumberOfStressPeriods; i++)
{
Dictionary<int, DatabaseParameter> temp = this.parametersByPeriod[i];
foreach (KeyValuePair<int, DatabaseParameter> d in temp)
{
if (d.Value.ParameterKey == paramKey && d.Value.PeriodKey == i && d.Value.StressEditorKey == editorKey && d.Value.ProfileType == className)
{
values[i - 1] = d.Value.ParameterValue;
}
}
}
return values;
}
Below shows getting the destination array from the dictionary, as indexes cannot be passed by reference
public static void AddParameters(double[] values, ClassList editor, string className, int paramKey)
{
// TODO: Maybe search all lists to eliminate the need for the class selector as a parameter
// TODO: Will throw an exception when nothing is found. Handle it
ParameterClass p = null;
foreach (ClassSelector c in Enum.GetValues(typeof(ClassSelector)))
{
p = editor.ClassLists[c].FirstOrDefault(f => f.Name == className);
if (p != null)
{
break;
}
}
// TODO: Notify that could not be found
if (p == null)
{
Log.Instance.LogMessage(LogLevel.Error, $"Unable to find class {className}");
return;
}
double[] dest = p.ClassVariables.editorParameters[paramKey];
AddParameterValues(values, ref dest);
}
And here's the AddParameterValues() method:
private static void AddParameterValues(double[] values, ref double[] destination)
{
if (values.Length != destination.Length)
{
return;
}
for (int i = 0; i < values.Length; i++)
{
destination[i] = values[i];
}
}
Debugging shows that some values are being loaded into the destination array, but some aren't. Could anyone tell me why this is? Or if not, point me toward some material?
Thank you for your time
I'm not that C# specialist but looking to following code as a C programmer
private double[] GetParameterValues(int paramKey, int editorKey, string className)
{
double[] values = new double[9];
//...
return values;
}
I would assume that the lifetime of values is only within the function GetParameterValues and the function GetParameterValues delivers the caller with reference to a dead variable.
What if you change the prototype to something like
private void GetParameterValues(ref double[] values, int paramKey, int editorKey, string className)

What is the difference between using ?? and an if not null block in C#?

Is there a difference between using ?? and if (foo == null) {...} else {...} in C#?
The ?? operator will only evaluate your value once, your version likely would evaluate it multiple times.
so
var baz = foo ?? bar;
should get evaluated as
var tmp = foo;
if(tmp == null)
{
tmp = bar;
}
var baz = tmp;
This is difference is important when foo is a function or a property which has a side effect in the getter.
private int _counter1 = 0;
private int _counter2 = 0;
private string Example1()
{
_counter1++;
if(_counter1 % 2 == 0)
return _counter1.ToString();
else
return null;
}
private string Example2()
{
_counter2++;
return _counter2.ToString();
}
Every time you do a var result = Example1() ?? Example2() the value of _counter1 should only go up by one and the value of _counter2 should only go up every other call.
//Equivalent if statement
var tmp = Example1();
if(tmp == null)
{
tmp = Example2();
}
var result = tmp;

Comparing on one element of on object in a list?

I have a custom class containing 2 public variables: 1 is a string and 1 is an integer. I then make a list of this class, in the list I need the string of the class to be unique, if the string already exists in the list I don't want to add it again but I do want to combine the corresponding integers. here is an example of the custom class and list.
public class myItems
{
public string itemName;
public int count;
}
List<myItems> items = new List<myItems>();
myItems e = new myItems();
e.symbol = "pencil";
e.count = 3;
items.Add(e);
myItems e1 = new myItems();
e1.symbol = "eraser";
e1.count = 4;
items.Add(e1);
myItems e2 = new myItems();
e1.symbol = "pencil";
e1.count = 3;
items.Add(e5);
So for the final list i want to it contain: pencil 7, eraser 4. I have been using the contains function on the list to check if it already exists but it only returns true if both the string and integer are the same.
Is there a way to only match on the string?
Another way to do it would be to use LINQ:
public class myItems
{
public string itemName;
public int count;
}
List<myItems> items = new List<myItems>();
myItems e = new myItems();
e.symbol = "pencil";
e.count = 3;
Add(items, e);
myItems e1 = new myItems();
e1.symbol = "eraser";
e1.count = 4;
Add(items, e1);
myItems e2 = new myItems();
e1.symbol = "pencil";
e1.count = 3;
Add(items, e5);
public void Add(List<myItems> list, myItems newItem)
{
var item = list.SingleOrDefault(x => x.symbol == newItem.symbol);
if(item != null)
{
item.count += newItem.count;
}
else
{
list.Add(newItem);
}
}
A dictionary might be well suited for this problem:
readonly Dictionary<string, int> _dict = new Dictionary<string, int>();
void InsertOrUpdate(string name, int count)
{
int previousCount = 0;
// item already in dictionary?
if (_dict.TryGetValue(name, out previousCount))
{
// add to count
count += previousCount;
}
_dict[name] = count;
}
void Main()
{
InsertOrUpdate("pencil", 3);
InsertOrUpdate("eraser", 3);
InsertOrUpdate("pencil", 4);
// print them
foreach (var item in _dict)
Console.WriteLine(item.Key + " " + item.Value);
}
You could add an Equals method to your class, or use LINQ with something like
items.Where(i => i.itemName == "pencil")
However, if all you are doing is keeping track of how many 'items' you have, would a Dictionary that maps itemNames to counts solve your problem easier? Then you would be able to do things like
// Assuming you want to add a new 'pencil' with a count of 3
int oldCount = 0;
items.TryGetValue("pencil", out oldCount);
items["pencil"] = oldCount + 3;
Usually see something like this called a Bag
Sure, write a custom Equals method
public override bool Equals(object o)
{
MyItems mi = o as MyItems;
if (mi == null)
return false;
if (itemName == null)
return mi.itemName == null;
return itemName.Equals(mi.itemName);
}
public override int HashCode()
{
return (itemName ?? string.Empty).HashCode();
}
That being said, you really should be using a dictionary/hash table instead, since a dictionary provides much faster lookup when you know what you want. A List implementation will cause the list to be searched in its entirety every time you want to add a MyItem to the list.
when you check if it contains and it returs true than you get the index and add the number to it. use that logic. it will work.

Categories

Resources