Possible unintended reference comparison in C# - c#

I am getting an Possible unintended reference comparison; to get a value comparison, cast the left hand side to type 'string' on the if statements in the GetPrice method. It shows its highlighted on all the "if (size == "Small")" statements. Here are my variables:
drinkType = GetDrinkType();
size = GetDrinkSize();
price = GetPrice(size);
private string GetDrinkType()
{
string theDrink;
theDrink = "None Selected";
if (rdoCoffee.Checked)
{
theDrink = "Coffee";
}
else if (rdoCoco.Checked)
{
theDrink = "Hot Chocolate";
}
else if (rdoSmoothie.Checked)
{
theDrink = "Smoothie";
}
return theDrink;
}
private string GetDrinkSize()
{
string theSize;
theSize = "None Selected";
if (rdoSmall.Checked)
{
theSize = "Small";
}
else if (rdoMedium.Checked)
{
theSize = "Medium";
}
else if (rdoLarge.Checked)
{
theSize = "Large";
}
return theSize;
}
private decimal GetPrice(object size)
{
decimal thePrice;
thePrice = 0;
if (size == "Small")
{
thePrice = 1.25m;
}
else if (size == "Medium")
{
thePrice = 2.50m;
}
else if (size == "Large")
{
thePrice = 3.35m;
}
return thePrice;
}

The size parameter is declared of type object, so the compiler doesn't know it's actually of type string. So it uses the default equality for type object, which is a reference comparison.
If you change the type of size to string, it will use the equality operator overload from the string class, which performs a value comparison.
private decimal GetPrice(string size)

The warning occurs because you are comparing a string to an object. If you change
if (size == "Small")
to
if (size.ToString() == "Small")
the warning will be removed.

Try changing the "object" in GetPrice to "string".

Since in GetPrize, the type of size is object, but you are comparing it to a string with size == "Large".
Change the comparison with "string text".Equals(object) as shown below
private decimal GetPrice(object size)
{
decimal thePrice = 0m;
if ("Small".Equals(size))
{
thePrice = 1.25m;
}
else if ("Medium".Equals(size))
{
thePrice = 2.50m;
}
else if ("Large".Equals(size))
{
thePrice = 3.35m;
}
return thePrice;
}

Related

Image.Tag of picture Box not working in if statement

I am making a memory game that compares two cards against themselves to see if they are the same. I do this by comparing the tag of the image in the picture box. All of the images have unique tags, however, when compared in an if statement, it passes over and treats it as false. This is the code for when the card is clicked on.
private void pictureBox1_Click(object sender, EventArgs e)
{
Image temp = Boxes[0];
pictureBox1.Tag = Boxes[0].Tag;
pictureBox1.Image = temp;
if (openBox1 == null)
{
openBox1 = pictureBox1;
}
else if (openBox1 != null && openBox2 == null)
{
openBox2 = pictureBox1;
}
if (openBox1 != null && openBox2 != null)
{
if (openBox1.Image.Tag == openBox2.Image.Tag)
{
openBox1 = null;
openBox2 = null;
}
else
{
openBox1.Image = Properties.Resources.card;
openBox2.Image = Properties.Resources.card;
openBox1 = null;
openBox2 = null;
}
}
}
This is how I am tagging the images:
List<int> Repeats = new List<int>();
int random;
bool test;
foreach (Image n in Album)//checks to see if image has been added
{
test = true;
while (test)
{
random = randy.Next(0, 16);
if (!Repeats.Contains(random))
{
Boxes[random] = n;
Boxes[random].Tag = n.Width * n.Height;
Repeats.Add(random);
test = false;
}
}
}
I have stepped into the program for myself, and monitored the variables. When I click two of the same card it just ignores that they are the same value.
The code doesn't works because boxing. int is a value type, to cast it to object (the type accepted by Tag) .net wraps the value type with a new object ('boxes' it). As object is a reference type and each tag has a different object the equality is not satisfied.
To make it work you must unbox the value, via a type cast or using the operator as:
//Unbox values before comparing
if (openBox1.Image.Tag as integer == openBox2.Image.Tag as integer)
//...

Return false if type properties equals null or 0

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);
}
}

Issues with > and < in C#

I have an issue with a small piece of code I've made.
For the code I have to make a small check. When the value of _mmdTextBox is bigger then 1999 it should give a MessageBx.Show("Value to high").
If the value is smaller then 0 there should be a MessageBox.Show("Value to low").
This is what I have made so far:
private void _mmdButton_Click(object sender, EventArgs e)
{
var value = _mmdTextBox.Text;
if (value > 1999 && value < 0)
{
MessageBox.Show("Value is to high");
}
else
{
// action
}
}
This is the error that I get when I do it like the code above:
Error 1 Operator '>' cannot be applied to operands of type 'string' and 'int'
int value;
if(Int32.TryParse(_mmdTextBox.Text, out value)
{
if (value > 1999)
{
MessageBox.Show("Value is too high");
}
else if(value < 0)
{
MessageBox.Show("Value is too low");
}
else
{
// action
}
}
else
{
// not a number
}
TextBox.Text returns string. So your value will be string. You can't compare string with an integer using < or > operators.
From MSDN;
All numeric and enumeration types define....
Try to convert your value to int if it is available.
int value;
if(Int32.TryParse(_mmdTextBox.Text, out value)
{
if (value > 1999)
{
MessageBox.Show("Value is too high");
}
if(value < 0)
{
MessageBox.Show("Value is too low");
}
}
C# is an strongly typed language and if you want to compare 2 value . They should be the same type . So you need to be convert text box text to int also you need a validation to be insure that the value which coming from text bot is int ok
I thought this will help full for you
Your if statement could be changed to look like this:
var value = Convert.ToInt32(_mmdTextBox.Text); //Convert to int in order to compare against an int
if (value > 1999)
{
MessageBox.Show("Value is to high");
}
else if (value < 0)
{
MessageBox.Show("Value is to low");
}
else
{
//Action
}
You are comparing the value as type string to type int.
int.TryParse() would be a better option for the int conversion as the user could enter anything. (Like in Erno De Weerd's answer)
You are comparing _mmdTextBox.Text which is string to constant of type int! It is impossible!
You should convert the former to int:
int value;
if(!int.TryParse(_mmdTextBox.Text, out value))
{
MessageBox.Show("Bad integer value in textbox");
return;
}
How can something be > 1999 AND < 0 ?
TryParse might be better for your conversion but this should work:
private void _mmdButton_Click(object sender, EventArgs e)
{
var value = Convert.ToInt32(_mmdTextBox.Text);
if (value > 1999)
{
MessageBox.Show("Value is too high");
}
else if (value < 0)
{
MessageBox.Show("Value is too low");
}
else
{
MessageBox.Show("Value is ok");
}
}
Your problem ist, that value is a string and not a number. You can use Parse or TryParse to solve it.
If you want to use .TryParse() make it look like this example from MSDN:
int number;
bool result = Int32.TryParse(value, out number);
if (result)
{
if (number > 1999 || number < 0)
{
MessageBox.Show("Value is invalid");
}
else
{
// action
}
}
else
{
//Show that the input is not a numeric value
}
Try it for instead of your if condition
if (Convert.ToInt32(value) > 1999 && !Convert.ToInt32(value)< 0)

Nullable Property throwing NullReferenceException on .HasValue

This line of (C#) code
if (!currentLap.S1.HasValue)
is giving me
System.NullReferenceException: Object reference not set to an instance of an object.
provided I'm sure that currentLap variable is instantiated (because it's being used a few lines before and it is a local variable) and it has following property:
private double? _s1;
[DefaultValue(null)]
[JsonConverter(typeof(ShortDoubleConverter))]
public double? S1
{
get { return _s1; }
set { _s1 = value; }
}
how can it possibly throw NullReferenceException? Can it be something to do with optimization on Release mode?
Thanks,
Stevo
EDIT:
here is full method code.
public void Update(DriverData driverData)
{
LapInfo currentLap = this.CurrentLap;
if (currentLap != null &&
this.LastDriverData != null &&
driverData.TotalLaps != this.LastDriverData.TotalLaps &&
driverData.InPits &&
driverData.Speed < 10 &&
!this.LastDriverData.InPits)
{
currentLap.Escaped = true;
}
this.LastDriverData = driverData;
if ((currentLap == null || currentLap.Lap != driverData.LapNumber) &&
!this.Laps.TryGetValue(driverData.LapNumber, out currentLap))
{
currentLap = new LapInfo() { Lap = driverData.LapNumber, Parent = this, Class = driverData.Class };
this.Laps.Add(driverData.LapNumber, currentLap);
int lapsCount = 0, completedDriverLaps = 0, cleanLaps = 0;
this.TotalLaps = driverData.TotalLaps;
//if it's not the first lap
if (driverData.TotalLaps > 0)
{
//previous lap
if (this.CurrentLap == null || !this.CurrentLap.Escaped)
{
this.CompletedLaps++;
if (this.CurrentLap == null || !this.CurrentLap.MaxIncident.HasValue)
this.CleanLaps++;
}
}
foreach (DriverLapsInfo laps in this.Parent.LapsByVehicle.Values)
{
lapsCount += laps.TotalLaps;
completedDriverLaps += laps.CompletedLaps;
cleanLaps += laps.CleanLaps;
}
this.Parent.Parent.SetLapsCount(driverData, lapsCount, driverData.Class, completedDriverLaps, cleanLaps);
}
this.CurrentLap = currentLap;
//add incidents
if (driverData.Incidents != null)
{
foreach (IncidentScore incident in driverData.Incidents)
{
this.CurrentLap.MaxIncident = Math.Max(this.CurrentLap.MaxIncident ?? 0, incident.Strength);
this.CurrentLap.Incidents++;
this.Incidents++;
}
}
LapInfo previousLap = null;
if ((this.PreviousLap == null || this.PreviousLap.Lap != driverData.TotalLaps) &&
this.Laps.TryGetValue(driverData.TotalLaps, out previousLap))
{
this.PreviousLap = previousLap;
if (!this.PreviousLap.Date.HasValue)
{
this.PreviousLap.Date = DateTime.UtcNow;
}
}
if (currentLap.Position == 0)
currentLap.Position = driverData.Position;
if (driverData.CurrentS1 > 0)
{
**if (!currentLap.S1.HasValue)**
{
this.UpdateBestS1(driverData.BestS1);
this.Parent.Parent.UpdateBestS1(driverData.BestS1, driverData.UniqueName);
currentLap.UpdateS1(driverData.CurrentS1, driverData);
//reset the best split set at the finish line
if (this.PreviousLap != null && this.PreviousLap.SplitBest < 0)
this.PreviousLap.SplitBest = 0;
}
if (driverData.CurrentS2.HasValue && driverData.CurrentS1.HasValue && !currentLap.S2.HasValue)
{
double s2 = driverData.CurrentS2.Value - driverData.CurrentS1.Value;
this.UpdateBestS2(s2);
this.Parent.Parent.UpdateBestS2(s2, driverData.UniqueName);
currentLap.UpdateS2(s2, driverData);
}
}
if (this.PreviousLap != null)
{
if (driverData.LastLap > 0)
{
if (!this.PreviousLap.S3.HasValue && driverData.LastS2.HasValue)
{
double s3 = driverData.LastLap.Value - driverData.LastS2.Value;
this.UpdateBestS3(s3);
this.Parent.Parent.UpdateBestS3(s3, driverData.UniqueName);
this.PreviousLap.UpdateS3(s3, driverData);
}
if (!this.PreviousLap.LapTime.HasValue)
{
double? bestLap = this.Parent.Parent.BestLap;
this.PreviousLap.UpdateLapTime(driverData, 0);
this.Parent.Parent.UpdateBestLap(this.PreviousLap, driverData.BestLap, driverData);
this.UpdateBestLap(driverData.BestLap, this.PreviousLap);
this.PreviousLap.UpdateLapTime(driverData, bestLap);
}
}
else
{
if (this.PreviousLap.SplitBest.HasValue)
this.PreviousLap.UpdateBestSplit();
if (this.PreviousLap.SplitSelf.HasValue)
this.PreviousLap.UpdateSelfSplit();
}
}
if (driverData.InPits)
{
switch (driverData.Sector)
{
case Sectors.Sector1:
if (previousLap != null)
previousLap.InPits = true;
break;
case Sectors.Sector3:
currentLap.InPits = true;
break;
}
}
//lap to speed
if (currentLap.TopSpeed < driverData.Speed)
{
driverData.TopSpeedLap = driverData.Speed;
currentLap.UpdateTopSpeed(driverData.Speed);
}
else
driverData.TopSpeedLap = currentLap.TopSpeed;
//overall top speed
if (this.TopSpeed < driverData.Speed)
{
driverData.TopSpeed = driverData.Speed;
this.TopSpeed = driverData.Speed;
this.Parent.Parent.UpdateTopSpeed(this.TopSpeed, driverData);
}
else
driverData.TopSpeed = this.TopSpeed;
}
There is no way on earth the code can make it to that line and currentLap beeing null.
Or am I going crazy? :)
.HasValue will not throw if the nullable reference is null, but a.b.HasValue will if a is null.
I suspect that currentLap == null. I know you say you're sure that currentLap is not null, but I think that's the most likely explanation. Can you post more code?
Update:
Thanks for posting your code.
This doesn't throw:
void Main() {
var f = new Foo();
Console.WriteLine (f.S1);
Console.WriteLine (f.S1.HasValue);
}
class Foo {
private double? _s1 = null;
public double? S1 {
get { return _s1; }
set { _s1 = value; }
}
}
Could you try to create a minimal reproduction? (minimal code that exhibits the issue)
Maybe have a look at the previous line of code :) - debugger often highlights the next line after the one where the NullReferenceException was actually thrown.

how to dynamically generate a formula and solive it by selecting multiple rows using linq

hi guys i have an array called tblCeMaintMatrix.ToArray()) with a result of :
[0]: { xValue = 0, Operator = 43 '+' }
[1]: { xValue = 1, Operator = 43 '+' }
[2]: { xValue = 12, Operator = 45 '-' }
i made a foreach loop to solve this however i encountered some errors. I think i confused the logic for this..
foreach (var a in tblCeMaintMatrix.ToArray())
{
{
value = operate((a.Operator).ToString(),a.xValue.Value );
}
decimal value2 = value;
}
private decimal operate(String a, Decimal value)
{
Decimal Value = 0;
if (a == "+")
{
Value = value + value;
}
if (a == "-")
{
Value= value - value;
}
if (a == "*")
{
Value = value * value;
}
if (a == "/")
{
Value = value / value;
}
return Value;
}
my problem is that
a) what is does is this :
0 + 0 = 0
1 + 1 = 2
12 - 12 = 0
instead of 0 + 1 -12.
b) it doesnt retain the value.
how can i modify this to solve the problem? thanks
Non-tested code, I wish it's correct..
decimal result = 0;
foreach (var a in tblCeMaintMatrix.ToArray())
{
{
result = operate((a.Operator).ToString(),a.xValue.Value,result);
}
}
private decimal operate(String a, Decimal value, Decimal result)
{
switch (a)
{
case "+": result += value; break;
case "-": result -= value; break;
case "*": result *= value; break;
case "/": result /= value; break;
default: result = value; break;
}
return result;
}
EDIT to ignore the first operator, I think you need to set your first operator to empty, like:
[0]: { xValue = 0, Operator = '' }
[1]: { xValue = 1, Operator = 43 '+' }
[2]: { xValue = 12, Operator = 45 '-' }
and see the modified Operate method.
Right now you are only passing a single value to your operate method, and using it as both operands. You need to also pass the running total of your code to the function:
Decimal total = 0;
foreach (var a in tblCeMaintMatrix.ToArray())
{
{
total = operate((a.Operator).ToString(),total, a.xValue.Value );
}
decimal value2 = value;
}
private decimal operate(String a, Decimal left, Decimal right)
{
Decimal Value = 0;
if (a == "+")
{
Value = left + right;
}
if (a == "-")
{
Value= left - right;
}
if (a == "*")
{
Value = left * right;
}
if (a == "/")
{
Value = left / right;
}
return Value;
}
It's not clear what's your using value2 to represent in your original function.

Categories

Resources