if then else vs the ternary operator ( ? :) in c# - c#

this.value1 and c.value1 can both be either null or non-null. So a total of 4 combinations to test. value2 can also be null or non-null.
Can the if-then-else's below be replaced by something shorter like use the ternary operator ( if then else using the ? : operators) - and would that be a bad practice for this specific case because we are testing 4 combinations for value1 and value2?
public override bool Equals(object obj)
{
bool value1_check = false;
bool value2_check = false;
var c = obj as ObjectType;
if (this.value1 != null)
value1_check = this.value1.Equals(c.value1);
else if ((this.value1 == null) && (c.value1 == null))
value1_check = true;
else if ((this.value1 == null) && (c.value1 != null))
value1_check = c.value1.Equals(this.value1);
if (this.value2 != null)
value2_check = this.value2.Equals(c.value2);
else if ((this.value2 == null) && (c.value2 == null))
value2_check = true;
else if ((this.value2 == null) && (c.value2 != null))
value2_check = c.value2.Equals(this.value2);
return (value1_check && value2_check);
}

You can call Object.Equals(), which already does all that.
return Equals(this.Value1, c.Value1)
&& Equals(this.Value2, c.Value2);

Actually, you might want the ?? Operator.
var lhs= this.value1 ?? c.value1 ?? null;
var rhs = c.value1 ?? this.value1 ?? null;
var value1Check = lhs == rhs
Should do the same thing as yours, but almost 100% less readable!

If your still wondering about the ternary option.
value1_check= this.value1!=null? this.value1.Equals(c.value1):(c.value1!=null?c.value.Equals(this.value):value1_check=true);

Related

How should NULL properties be handled in a CompareTo method?

I want to compare 2 instances of a class to see if they are equal.
I created this method that is faulty:
public int CompareTo(AdminEngineTableRowModel other)
{
int result;
if (other != null)
{
result = NXSTDT.CompareTo(other.NXSTDT);
if (result == 0)
result = DALOC.CompareTo(other.DALOC);
if (result == 0)
result = DealerID.CompareTo(other.DealerID);
if (result == 0)
result = Status.CompareTo(other.Status);
if (result == 0)
result = OrderNumber.CompareTo(other.OrderNumber);
if (result == 0)
result = Dealership.CompareTo(other.Dealership);
if (result == 0)
result = Serial.CompareTo(other.Serial);
if (result == 0)
result = Model.CompareTo(other.Model);
if (result == 0)
result = OrderDate.CompareTo(other.OrderDate);
if (result == 0)
result = StartDate.CompareTo(other.StartDate);
if (result == 0)
result = Confirmed.CompareTo(other.Confirmed);
if (result == 0)
result = Deposit.CompareTo(other.Deposit);
if (result == 0)
result = Engine.CompareTo(other.Engine);
if (result == 0)
result = Color.CompareTo(other.Color);
if (result == 0)
result = Name.CompareTo(other.Name);
}
else
{
result = 1;
}
return result;
}
The problem comes when any of the properties, like the first string NXSTDT is NULL:
result = NULL.CompareTo(other.NXSTDT); // This causes an error
I could create a class ctor constructor to initialize all of the properties, or I could edit the CompareTo method to check that each property is not null before I test it:
public int CompareTo(AdminEngineTableRowModel other)
{
int result;
if (other != null)
{
if ((NXSTDT == null) && (other.NXSTDT != null))
result = 1;
if (result == 0)
result = NXSTDT.CompareTo(other.NXSTDT);
if ((DALOC == null) && (other.DALOC != null))
result = 1;
if (result == 0)
result = DALOC.CompareTo(other.DALOC);
// {snip}
}
else
{
result = 1;
}
return result;
}
That just seems like poor programming.
Is there a better way to do this?
One idea would be to write a generic Compare<T> method that works will any object that implements IComparable<T>. Then you can write the null-handling once and not worry about it again. This does assume that the types you're comparing implement that interface.
public static int Compare<T>(T first, T second) where T : IComparable<T>
{
if (ReferenceEquals(first, second)) return 0;
if (first == null) return -1;
return first.CompareTo(second);
}
Then your code would look like:
public int CompareTo(AdminEngineTableRowModel other)
{
if (ReferenceEquals(this, other)) return 0;
if (other == null) return 1;
int result = Compare(NXSTDT, other.NXSTDT);
if (result != 0) return result;
result = Compare(DALOC, other.DALOC);
if (result != 0) return result;
result = Compare(DealerID, other.DealerID);
if (result != 0) return result;
result = Compare(Status, other.Status);
if (result != 0) return result;
result = Compare(OrderNumber, other.OrderNumber);
if (result != 0) return result;
result = Compare(Dealership, other.Dealership);
if (result != 0) return result;
result = Compare(Serial, other.Serial);
if (result != 0) return result;
result = Compare(Model, other.Model);
if (result != 0) return result;
result = Compare(OrderDate, other.OrderDate);
if (result != 0) return result;
result = Compare(StartDate, other.StartDate);
if (result != 0) return result;
result = Compare(Confirmed, other.Confirmed);
if (result != 0) return result;
result = Compare(Deposit, other.Deposit);
if (result != 0) return result;
result = Compare(Engine, other.Engine);
if (result != 0) return result;
result = Compare(Color, other.Color);
if (result != 0) return result;
return Compare(Name, other.Name);
}
If you just want to compare 2 instances for equality, it is simpler to use a boolean Equals() method, like so:
public bool Equals(AdminEngineTableRowModel other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
// If applicable, use <Property>.Equals(other.<Property>)
// For example, to compare strings according to culture
// and case
return (NXSTDT == other.NXSTDT &&
DALOC == other.DALOC &&
DealerId == other.DealerId &&
Status == other.Status &&
OrderNumber == other.OrderNumber &&
....);
}
This way, due to short-circuiting, the method will return false on the first un-equal property value.
If you use at least C# 9 you don't need to actually implement anything, just add record keyword to your class:
public record class YourClass {}
it will automatically generate the Equals, GetHashCode methods among others and overload the == operator so you can simply do:
if (instanceA == instanceB) {}
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/types/records

Multithread, Linq to Sql, ConcurrentDictonary Fails Remove

I have a ConcurrentDictionary of Attributes for products. These attributes have the product ID and values for the names of the attribute and any options the attribute has. I have this ConcurrentDictionary because I have threads that are created to handle each attribute in the dictionary by attribute name.
if (knownAttribute.AttributeType.Value.Equals("Product Specification"))
{
Console.WriteLine("Started a thread for: " + knownAttribute.AttributeTypeId + ", " + knownAttribute.Value);
while (true)
{
/* if (AS400SpecificationAttributes.IsEmpty && knownSpecificationBag.IsEmpty && gatherRowsTasks.All(x => x.IsCompleted))
break;*/
AS400SpecificationAttribute AS400SpecificationAttributeWork = null;
AS400SpecificationAttributeWork = knownSpecificationBag.Keys.FirstOrDefault(x => x.AttributeName == knownAttribute.Value);
if (AS400SpecificationAttributeWork != null)
{
var product = ctx.Products.FirstOrDefault(x => x.ProductNumber == AS400SpecificationAttributeWork.ProductNumber);
if (product == null)
continue;
var productAttribute = new ProductAttribute();
productAttribute.Attribute = knownAttribute;
if (AS400SpecificationAttributeWork.AttributeValue != null)
{
var knownAttributeOption = ctx.AttributeOptions.FirstOrDefault(x => x.Attribute.Equals(knownAttribute) && x.Value.Equals(AS400SpecificationAttributeWork.AttributeValue));
if (knownAttributeOption == null)
{
knownAttributeOption = new AttributeOption();
knownAttributeOption.Value = AS400SpecificationAttributeWork.AttributeValue;
knownAttributeOption.Attribute = knownAttribute;
ctx.AttributeOptions.InsertOnSubmit(knownAttributeOption);
ctx.SubmitChanges();
}
productAttribute.AttributeOption = knownAttributeOption;
productAttribute.AttributeOptionId = knownAttributeOption.Id;
}
product.ProductAttributes.Add(productAttribute);
ctx.SubmitChanges();
string tmpstr = null;
if (!knownSpecificationBag.TryRemove(AS400SpecificationAttributeWork, out tmpstr))
Thread.Sleep(50);
}
else
{
if (tryCounter < 5)
{
tryCounter++;
Thread.Sleep(1000);
Console.WriteLine("Thread waiting for work: Product Specification:" + knownAttribute.Value);
continue;
}
else
{
int outVal;
threadTracker.TryRemove("Product Specification:" + knownAttribute.Value, out outVal);
Console.WriteLine("Closing Thread: Product Specification:" + knownAttribute.Value);
break;
}
}
Thread.Sleep(50);
}
It seems like the following Attribute element refuses to be removed.
I don't understand why. If i put it in a while(!dic.tryRemove(ele)) it will forever be stuck and never move from there.
There may be an error somewhere within the thread but I have no idea why.
This statement
if (!knownSpecificationBag.TryRemove(AS400SpecificationAttributeWork, out tmpstr))
will always return true or false. It won't block. That's the behavior of ConcurrentDictionary. It will return false if the key is not in the dictionary.
If you're looping while that method returns false and it's stuck, that means that the item isn't in the dictionary when the loop begins. Either it either was never in the dictionary or that another thread already removed it.
Is your intention to loop until the item is not in the dictionary?
You could try this:
if (!knownSpecificationBag.TryRemove(AS400SpecificationAttributeWork, out tmpstr)
&& !knownSpecificationBag.ContainsKey(AS400SpecificationAttributeWork))
Implement proper equals and gethashcode when using TryRemove
public override int GetHashCode()
{
return new { this.name, this.value, this.group, this.productNumber }.GetHashCode();
}
public bool Equals(AS400SpecificationAttribute other)
{
if (other == null)
return false;
return (this.ProductNumber.Equals(other.productNumber) && ((this.group != null && this.group.Equals(other.AttributeGroup)) || (this.group == null && other.AttributeGroup == null)) && ((this.name!= null && this.name.Equals(other.AttributeName)) || (this.name == null && other.AttributeName == null)) && ((this.value != null && this.value.ToUpper().Equals(other.AttributeValue.ToUpper())) || (this.value == null && other.AttributeValue == null)));
}

How can i implement == and check for null in c# [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicates:
What is “Best Practice” For Comparing Two Instances of a Reference Type?
How do I check for nulls in an '==' operator overload without infinite recursion?
I have a class called "Criterion" and i want to implement == operator,but I'm struggling with the following problem :
When i implement the == operator, I'm checking if one or both of my instances are null, but when i do it, it causes a recursive call for == and then i get "StackOverflow" (he he) exception.
Technically i can implement the Equals operator and not override the ==, but the code will be much more readable if i implement the == operator.
Here is my code :
public static bool operator == (Criterion c1, Criterion c2)
{
if (null == c1)
{
if (null == c2)
return true;
return false;
}
if (null == c2)
return false;
if ((c1.mId == c2.mId) && (c1.mName == c2.mName))
return true;
return false;
}
Try ReferenceEquals:
public static bool operator ==(Criterion c1, Criterion c2) {
var nullC1 = ReferenceEquals(null, c1);
var nullC2 = ReferenceEquals(null, c2);
if (nullC1 && nullC2)
return true;
if (!nullC1 && !nullC2)
if (c1.mId == c2.mId && c1.mName == c2.mName)
return true;
return false;
}
I'd do it like this:
bool isC1Null = Object.Equals(c1, null)
bool isC2Null = Object.Equals(c2, null)
if (isC1Null ^ isC2Null)
{
return false
}
if (isC1Null && isC2Null)
{
return true
}
//your code

Neatest/most idiomatic way to rewrite this If in C#

I have this if-else statement which does what I want. What it's doing is pretty straightforward as you should be able to tell.
if (width != null && height != null)
{
if (top != null && left != null)
{
ret.type = VMLDimensionType.full;
}
else
{
ret.type = VMLDimensionType.size;
}
}
else
{
if (top != null && left != null)
{
ret.type = VMLDimensionType.positon;
}
else
{
ret.type = VMLDimensionType.unset;
}
}
The enum being referred to is:
private enum VMLDimensionType
{
unset = 0,
full = 1,
size = 2,
position = 3
}
It's so straightforward I'm sure there's a much more terse and more readable way to express this.
NB If it wasn't for the ridiculous 'one-brace per line' rule that VS imposes by default I probably wouldn't be so bothered. Eg in VB I could lose about 10 lines from this code block! (any thoughts on that as an aside?)
bool hasPosition = (top != null && left != null);
bool hasSize = (width != null && height != null);
if (hasSize)
{
ret.type = hasPosition ? VMLDimensionType.full : VMLDimensionType.size;
}
else
{
ret.type = hasPosition ? VMLDimensionType.positon : VMLDimensionType.unset;
}
One option would be to make VMLDimensionType a Flags enumeration:
[Flags]
enum VMLDimensionType
{
Unset = 0,
Size = 1,
Position = 1 << 1,
Full = Size | Position
}
And then:
ret.Type = VMLDimensionType.Unset;
if(width != null && height != null)
ret.Type |= VMLDimensionType.Size;
if (top != null && left != null)
ret.Type |= VMLDimensionType.Position;
How about this:
bool hasSize = width != null && height != null;
bool hasPosition = top != null && left != null;
if (hasSize && hasPosition)
{
ret.type = VMLDimensionType.full;
}
else if (hasSize && !hasPosition)
{
ret.type = VMLDimensionType.size;
}
else if (!hasSize && hasPosition)
{
ret.type = VMLDimensionType.positon;
}
else
{
ret.type = VMLDimensionType.unset;
}
I would like to extract GetDimensionType() method.
And make it not so small, but more readable and self-descriptive.
private VMLDimensionType GetDimensionType()
{
bool hasSize = width != null && height != null;
bool hasPosition = top != null && left != null;
if (hasSize && hasPosition)
return VMLDimensionType.full;
if (hasSize)
return VMLDimensionType.size;
if (hasPosition)
return VMLDimensionType.positon;
return VMLDimensionType.unset;
}
Usage:
ret.type = GetDimensionType();
What about this:
if(width != null && height != null)
ret.type = top != null && left != null ? VMLDimensionType.full : VMLDimensionType.size;
else
ret.type = top != null && left != null ? VMLDimensionType.positon : VMLDimensionType.unset;

Determine value of object in C#

What would be the best way to determine if an object equals number zero (0) or string.empty in C#?
EDIT: The object can equal any built-in System.Value type or reference type.
Source Code:
public void MyMethod(object input1, object input2)
{
bool result = false;
object compare = new object();
if(input != null && input2 != null)
{
if(input1 is IComparable && input2 is IComparable)
{
//do check for zero or string.empty
//if input1 equals to zero or string.empty
result = object.Equals(input2);
//if input1 not equals to zero or string.empty
result = object.Equals(input1) && object.Equals(input2); //yes not valid, but this is what I want to accomplish
}
}
}
Using Jonathan Holland code sample with a minor modification, here is the solution that worked:
static bool IsZeroOrEmpty(object o1)
{
bool Passed = false;
object ZeroValue = 0;
if(o1 != null)
{
if(o1.GetType().IsValueType)
{
Passed = (o1 as System.ValueType).Equals(Convert.ChangeType(ZeroValue, o1.GetType()))
}
else
{
if (o1.GetType() == typeof(String))
{
Passed = o1.Equals(String.Empty);
}
}
}
return Passed;
}
What's wrong with this?
public static bool IsZeroOrEmptyString(object obj)
{
if (obj == null)
return false;
else if (obj.Equals(0) || obj.Equals(""))
return true;
else
return false;
}
Michael, you need to provide a little bit more information here.
strings can be compared to null or string.Empty by using the method
string x = "Some String"
if( string.IsNullOrEmpty(string input) ) { ... }
int, decimals, doubles (and other numeric value-types) can be compared to 0 (zero) with a simple == test
int x = 0;
if(x == 0) { ... }
You can also have nullable value-types also by using the ? operator when you instantiate them. This allows you to set a value type as null.
int? x = null;
if( !x.HasValue ) { }
For any other object, a simple == null test will tell you if its null or not
object o = new object();
if( o != null ) { ... }
Hope that sheds some light on things.
Not quite sure the reasoning behind this, because .Equals is reference equality on reference types, and value equality on value types.
This seems to work, but I doubt its what you want:
static bool IsZeroOrEmpty(object o1)
{
if (o1 == null)
return false;
if (o1.GetType().IsValueType)
{
return (o1 as System.ValueType).Equals(0);
}
else
{
if (o1.GetType() == typeof(String))
{
return o1.Equals(String.Empty);
}
return o1.Equals(0);
}
}
Do you mean null or string.empty, if you're talking about strings?
if (String.IsNullOrEmpty(obj as string)) { ... do something }
Oisin
In the first case by testing if it is null. In the second case by testing if it is string.empty (you answered your own question).
I should add that an object can never be equal to 0. An object variable can have a null reference though (in reality that means the variable has the value of 0; there is no object in this case though)
obj => obj is int && (int)obj == 0 || obj is string && (string)obj == string.Empty

Categories

Resources