I have a rule that runs against an object before an actual evaluation takes place. The rule checks that the collection is not null and that the elements have a valid id (greater than zero). When testing with a null collection this behaves as expected. However when testing with a non null collection with invalid arguments the evaluation does not behave as I expect. Without parenthesis the expression containing the null coalescing operator returns true but with parenthesis it returns the correct value. Trying to understand how this changes the evaluation of operations as I would imagine them to evaluate to the same result in both cases.
var testRule = new CollectionRule(null);
testRule.Verify();
//Verify => False
testRule.Verify2();
//Verify2 => False
testRule = new CollectionRule(new int[] { -1 });
testRule.Verify();
//Verify => True
testRule.Verify2();
//Verify2 => False
public class CollectionRule
{
private IEnumerable<int> _elements;
public CollectionRule(IEnumerable<int> elements) => _elements = elements;
public bool Verify()
{
bool result = _elements?.GetEnumerator().MoveNext() ?? false && _elements.All(i => i > 0);
System.Diagnostics.Debug.WriteLine($"Verify => {result}");
return result;
}
public bool Verify2()
{
bool result = (_elements?.GetEnumerator().MoveNext() ?? false) && _elements.All(i => i > 0);
System.Diagnostics.Debug.WriteLine($"Verify2 => {result}");
return result;
}
}
&& has a higher precedence than ??, so this:
a ?? b && c
will be evaluated like:
a ?? (b && c)
In your case b is false, and false && c is just false, so the whole thing simplifies down to a ?? false.
Related
is it possible to compare several strings between them according to different conditions ?
I have 4 strings to compare between them:
If the four are the same => one condition
(example : A,A,A,A)
If only one different value and the rest null => a condition
(example : A, A, null, A or A, null, null, null )
If there are at least two different strings other than null => another condition
(example : A,B,A,A or A,B,Null, Null)
do you know how I can do it, in a clean way, without making an "if" for each possible combination?
Put the strings in a collection and start the LINQ engine :)
If the four are the same => one condition (example : A,A,A,A)
bool allSame = !strings.Distinct().Skip(1).Any(); // or Distinct().Count() == 1
If only one different value and the rest null
bool oneNonNull = strings.Count(s => s != null).Count() == 1;
If there are at least two different strings other than null
bool twoNonNull = strings.Where(s => s != null).Take(2).Count() == 2;
If you absolutely don't want to use if statements, you could use delegates with anonymous functions like so:
public void CompareStrings(List<string> stringsToCompare) {
Func<List<string>, bool> allSame = delegate (List<string> input)
{
return input.Distinct().Count() == stringsToCompare.Count;
};
Func<List<string>, bool> oneDifferent = delegate (List<string> input)
{
return input.Distinct().Count() == stringsToCompare.Count - 1;
};
Func<List<string>, bool> twoDifferent = delegate (List<string> input)
{
return input.Distinct().Count() == stringsToCompare.Count - 2;
};
Console.WriteLine(allSame);
Console.WriteLine(oneDifferent);
Console.WriteLine(twoDifferent);
}
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I was wondering what was the most clean and understandable syntax for doing condition checks on nullable bools.
Is the following good or bad coding style? Is there a way to express the condition better/more cleanly?
bool? nullableBool = true;
if (nullableBool ?? false) { ... }
else { ... }
especially the if (nullableBool ?? false) part. I don't like the if (x.HasValue && x.Value) style ...
(not sure whether the question has been asked before ... couldn't find something similar with the search)
I think a lot of people concentrate on the fact that this value is nullable, and don't think about what they actually want :)
bool? nullableBool = true;
if (nullableBool == true) { ... } // true
else { ... } // false or null
Or if you want more options...
bool? nullableBool = true;
if (nullableBool == true) { ... } // true
else if (nullableBool == false) { ... } // false
else { ... } // null
(nullableBool == true) will never return true if the bool? is null :P
How about using GetValueOrDefault, which is pretty self-explaining and allows to use whatever default you want:
if (nullableBool.GetValueOrDefault(false)) {
}
You may not like it, but personally I find
if (x.HasValue && x.Value)
the most readable. It makes it clear you are working with a nullable type and it makes it clear you are first checking whether the nullable type has a value before acting on it conditionally.
If you take your version and replace the variable with x also it reads:
if (x ?? false)
Is that as clear? Is it obvious x is a nullable type? I'll let you decide.
Another way is to use constant pattern matching:
if (nullableBool is true) {}
if (nullableBool is false) {}
if (nullableBool is null) {}
Unlike the operator ==, when reading the code, this will distinguish the nullable type check from ordinary "code with a smell".
If you want to treat a null as false, then I would say that the most succinct way to do that is to use the null coalesce operator (??), as you describe:
if (nullableBool ?? false) { ... }
Just think of bool? as having 3 values, then things get easier:
if (someNullableBool == true) // only if true
if (someNullableBool == false) // only if false
if (someNullableBool == null) // only if null
Actually I think that (nullableBool ?? false) is a legitimate option especially when you are trying to evaluate a nullable bool in linq.
For example:
array.Select(v => v.nullableBool ?? false)
(from v in array where v.nullableBool ?? false)
Is cleaner in my opinion as opposed to:
array.Select(v => v.nullableBool.HasValue ? v.nullableBool.Value : false)
(from v in array where v.nullableBool.HasValue ? v.nullableBool.Value : false)
Use extensions.
public static class NullableMixin {
public static bool IsTrue(this System.Nullable<bool> val) {
return val == true;
}
public static bool IsFalse(this System.Nullable<bool> val) {
return val == false;
}
public static bool IsNull(this System.Nullable<bool> val) {
return val == null;
}
public static bool IsNotNull(this System.Nullable<bool> val) {
return val.HasValue;
}
}
Nullable<bool> value = null;
if(value.IsTrue()) {
// do something with it
}
Lets check how the comparison with null is defined:
static void Main()
{
Console.WriteLine($"null != null => {null != null}");
Console.WriteLine($"null == null => {null == null}");
Console.WriteLine($"null != true => {null != true}");
Console.WriteLine($"null == true => {null == true}");
Console.WriteLine($"null != false => {null != false}");
Console.WriteLine($"null == false => {null == false}");
}
and the results are:
null != null => False
null == null => True
null != true => True
null == true => False
null != false => True
null == false => False
So you can safely use:
// check if null or false
if (nullable != true) ...
// check if null or true
if (nullable != false) ...
// check if true or false
if (nullable != null) ...
If you only want to test for true against null/false, One I've just used and reads quite well is
bool? someCondition = null
if (someCondition.Equals(true))
...
I think its up to you. I certainly think the .HasValue approach is more readable, especially with developers not familiar with the ?? syntax.
The other point of a nullable boolean type is that it is tristate, so you may want to do something else when it is just null, and not default to false.
Given enum
public enum PublishMode { Edit, View }
you can do it like here
void MyMethod(PublishMode? mode)
{
var publishMode = mode ?? PublishMode.Edit;
//or
if (mode?? PublishMode.Edit == someValue)
....
}
If you're in a situation where you don't have control over whether part of the condition is checking a nullable value, you can always try the following:
if( someInt == 6 && someNullableBool == null ? false : (bool)someNullableBool){
//perform your actions if true
}
I know it's not exactly a purist approach putting a ternary in an if statement but it does resolve the issue cleanly.
This is, of course, a manual way of saying GetValueOrDefault(false)
Assume I have a list of binary parameters (in reality it is a list of checkboxes' IsChecked.Value property). I'm trying to get the bool? (ternary) result that:
is true if all the elements in the list are true
is false if all the elements in the list are false
is null in all other cases, thus there are both true and false elements in the list or the list is empty
Until now I came up with the solution that requires iterating over the list twice (checking whether all elements are either true or false) and then comparing the results to deciding whether to return true, false or null.
This is my code:
bool checkTrue = myListOfBooleans.All(l => l);
bool checkFalse = myListOfBooleans.All(l => !l);
bool? result = (!checkTrue && !checkFalse) ? null : (bool?)checkTrue;
How can I achieve it in only one iteration over the list?
You could do that by using Aggegrate
public bool? AllSameValue(List<bool> myListOfBooleans)
{
if(myListOfBooleans.Count == 0) return null; // or whatever value makes sense
return myListOfBooleans.Cast<bool?>().Aggregate((c, a) => c == a ? a : null);
}
That casts your values to bool? so that you can then compare them and return the value if that they all match or null if there is a difference.
Of course you could exit early by taking the first one and using All to see if the rest match or not.
public bool? AllSameValue(List<bool> myListOfBooleans)
{
if(myListOfBooleans.Count == 0) return null; // or whatever value makes sense
bool first = myListOfBooleans[0];
return myListOfBooleans.All(x => x == first ) ? first : null;
}
You can simply count the true values:
int c = myListOfBooleans.Count(l => l);
bool? result = c == myListOfBooleans.Count
? (bool?)true
: (c == 0 ? (bool?)false : null);
Note that this is true for an empty list, you may want to tweak that according to your required logic.
For a better performance (though I don't think it matters in a UI context) you could write an extension that could even return early if the result is clear (instead of iterating through the whole list):
public static bool? AllOrNothing(this IEnumerable<bool> list)
{
if (list == null) throw new ArgumentNullException(nameof(list));
using(var enumerator = list.GetEnumerator())
{
if (!enumerator.MoveNext())
return null; // or true or false, what you need for an empty list
bool? current = enumerator.Current;
while(enumerator.MoveNext())
if (current != enumerator.Current) return null;
return current;
}
}
And use it:
bool? result = myListOfBooleans.AllOrNothing();
when I use someList.Where(t => t.isTrue = true) nothing happens. But when I use code as given below,
if(someList.Where(t => t.isTrue = true).Count() > 0)
return;
All items inside the list are set to true. Why this is happening?
Edit : I am not trying to assign or compare anything. I am curious about why this happens when used with if.
This happens because you use an assignment instead (=) of equality compare (==).
Also it only happens when you use Count because LINQ only evaluates the lambda expression when it has to get a value.
var q = someList.Where(t => t.isTrue = true); // Nothing will happen
q.ToList() // would happen here
if(q.Count() > 0 ) { .. } // Also here
To compare and not assign the value you should use:
var q = someList.Where(t => t.isTrue == true);
var q = someList.Where(t => t.isTrue); // Or simpler
The reason the compiler allows this is because assignment is an expression that has a value. For example :
int a = 10;
int b;
int c = (b = a) ; // (a=b) is of type int even though it also assigns a value, and b and c will have a value of 10
In your case, the assignment of a bool has type bool, which happens to be a valid return value for a lambda passed to Where
All items inside the list are set to true when you use = and then evaluates the expression by using Count().
As the isTrue is a boolean this would be enough to count the values which is true
if(someList.Where(t => t.isTrue).Count() > 0)
return;
As an alternative to checking if the count is higher than 0 you can use the Any method which already does just that
if(someList.Where(t => t.isTrue).Any()) // Any returns true if there are any elements in the collection
return;
You can further simplify this with an overload of Any that takes the condition as a parameter, skiping the additional Where
if(someList.Any(t => t.isTrue)) // This overload takes a function that returns a boolean like Where does and returns true if there is at least 1 element that matches the condition
return;
There are three properties in the object
{obj.prop1, obj.prop2, obj.prop3} These properties are NULLABLE INTEGER
And I need to validate either all three properties should contain some value or all three properties are null.
Here's the validation
if (!((!obj.prop1.HasValue && !obj.prop2.HasValue && !obj.prop3.HasValue) ||
(obj.prop1.HasValue && obj.prop2.HasValue && obj.prop3.HasValue)))
{
//throw new Exception("");
}
Is there any better way to do it via some other Logical operators?
You can try this
if (obj.prop1.HasValue != obj.prop2.HasValue || obj.prop2.HasValue != obj.prop3.HasValue)
throw...
The expression above yields:
p1.HasValue p2.HasValue p3.HasValue
==========================================================================
false false false => false || false => false
false false true => false || true => true
false true false => true || true => true
true false false => true || false => true
false true true => true || false => true
true true false => false || true => true
true false true => true || true => true
true true true => false || false => false
You could use null coalescing for the null check, but you would still need to verify if all items do actually have a value for the other:
if((obj.prop1 ?? obj.prop2 ?? obj.prop3) == null
|| (obj.prop1.HasValue && obj.prop2.HasValue && obj.prop3.HasValue))
{
// conditional block
}
However, I think the original way you have it is more understandable to an average user.
I don't know of a logical operator that can make the code look nicer, but what I often do is wrap the functionality in to a method with a name that describes the test. This helps reduce the code size, and makes the code "self documenting".
Here's an example method that will test a bunch of objects to see if they are "partially null".
private static bool ArePartiallyNull(params object[] values)
{
if(values.Length <= 1)
return false;
var isNull = values[0] == null;
for(var i = 1;i < values.Length;i++)
{
if(isNull != (values[i] == null))
return true;
}
return false;
}
And this method in action: https://dotnetfiddle.net/6QIpDF
public class Program
{
public static void Main()
{
int? one = 1;
int? two = 1;
int? three = 1;
int? nullOne = null;
int? nullTwo = null;
int? nullThree = null;
Console.WriteLine(ArePartiallyNull(one, two, three));
Console.WriteLine(ArePartiallyNull(nullOne, nullTwo, nullThree));
Console.WriteLine(ArePartiallyNull(one, two, nullThree));
}
private static bool ArePartiallyNull(params object[] values)
{
if(values.Length <= 1)
return false;
var isNull = values[0] == null;
for(var i = 1;i < values.Length;i++)
{
if(isNull != (values[i] == null))
return true;
}
return false;
}
}
There are actually a handful of ways you can go about this depending on how "automatic" you want it to be when you add new properties for the object. If you don't mind updated your check each time you add a new property, I would just go with a simple method for comparison.
First, the example you have provided is a just fine approach. This is actually going to be the most performant way to perform the check. The downside is it is overly verbose, and doesn't scale well if you plan to add a lot more properties to the object.
The next method you could consider is to create a custom function that compares the properties for you. This way, when you use the function in your code, it is a bit less verbose. The function below will take as many int? variables you want to throw at it, and verify that they all either have a value, or don't have a value.
bool Test(params int?[] props)
{
bool? lastValue = null;
foreach(int? p in props)
{
// We haven't got a status yet so we just use the status for the first prop
if (lastValue.HasValue == false)
lastValue = p.HasValue;
else
{
// If the status of this next prop doesn't match the first, we know it is false
if (p.HasValue != lastValue.Value)
return false;
}
}
// Default back to true since we didn't identify any issues.
return true;
}
The last option I would propose would be to use reflection. With reflection, you could loop over the properties and check each one using similar logic to the function above. The benefit of this approach is that you do not need to adjust your logic as you add new properties. The downside is performance.
If you just want to make sure that all three have a value or don't have a value (regardless of what the value is) then
bool AllAreTrueOrFalse(params bool[] values)
{
return values.All(value=>value) || !values.Any(value=>value);
}
var allTrueOrFalse = AllAreTrueOrFalse(obj.prop1.HasValue, obj.prop2.HasValue,
obj.prop3.HasValue);