Getting compile time error while using lambda in C# - c#

I am trying to use FirstOrDefault in my code but getting compile time error.
Cannot implicitly convert type Priority to bool
public class Priority
{
public string Name { get; set; }
public string Id { get; set; }
public string Default { get; set; }
}
public class ProcedureStatus
{
public string Id { get; set; }
public Priorities Priorities { get; set; }
}
public class Priorities
{
public List<Priority> Priority { get; set; }
}
foreach (Priority priority in status.Priorities.Priority)
{
if (priority.Default == "true" && grid.Priority == null)
{
grid.Priority = priority.Id;
grid.PriorityText = priority.Name;
SetPriority(gridRow);
break;
}
else if (status.Priorities.Priority.FirstOrDefault(x => x.Id == priority.Id))
priority.Default = "true";
}
How to use FirstOrDefault in my scenario.

You are using status.Priorities.Priority.FirstOrDefault(x => x.Id == priority.Id) in an if clause.
The if clause is expecting an expression that returns a bool, but your expression returns a Priority.
Aside from that, it looks like the if clause is redundant, since you are iterating the properties via a foreach and trying to get the current item from the list you are already iterating. If you just want to iterate the list, you don't need the if clause.
The way you would typically use FirstOrDefault would be like this:
var priority = status.Priorities.Priority.FirstOrDefault(x => x.Id == priorityId)`;
if (priority != null)
{
\\ ...
}
where priorityId is the ID of the priority you are looking for.
This does not seem useful inside you foreach loop though.
(Even after your question update, you still have the same if clause inside the foreach. It's just after an if/else now.)

The problem
The problem is not related to Lambda expressions (x => blablabla syntax) but related to what a specific function FirstOrDefault() returns and how to use it in an if-else-elseif scenario.
Analysis
The code you wrote could be written in two steps as:
if (priority.Default == "true" && grid.Priority == null)
{
// your if block
}
else
{
Priority firstPriority = status.Priorities.Priority.FirstOrDefault(x => x.Id == priority.Id);
// Same exact error you got... Cannot implicitly convert type Priority to bool
if (firstPriority) {
priority.Default = "true";
}
}
Now it is more easy to understand what the problem is... if, else and else if statements need a logical expression to work. That can be made either using a bool variable or doing a check/evaluation that returns true/false.
Solution
There are many different ways to address the problem:
You could use a function that directly returns a boolean like Any(), that would be useful if you do not need to use the object matching the x => x.Id == priority.Id.
You could use FirstOrDefault() but changing your else if to convert it into something that return a logic expression. This would be useful if you need to later work with that element.
Using the Any() function
else if (status.Priorities.Priority.Any(x => x.Id == priority.Id))
{
priority.Default = "true"; // Dumb question, why the Default property is not of type bool???
}
Using the FirstOrDefault()
Note: you have already been given this option in other answers. Ergwun's answer and Braulio's answer so far.
As per the documentation of the function I linked and what its name suggests, if the FirstOrDefault() function does not find anything, it returns null. So you could check it whatever it returns is null or not.
This could be done in a couple of ways. Depending on if you need to later work with whatever the function returns or not.
else if (status.Priorities.Priority.FirstOrDefault(x => x.Id == priority.Id) != null)
{
priority.Default = "true";
}
or
if (priority.Default == "true" && grid.Priority == null)
{
// your if block
}
else
{
Priority firstPriority = status.Priorities.Priority.FirstOrDefault(x => x.Id == priority.Id);
if (firstPriority != null) {
priority.Default = "true";
Console.WriteLine("The description of the priority if the Id XXXX is: " + firstPriority.Description);
}
}

Best way it's to compare if your object is not null after the research
foreach (Priority priority in status.Priorities.Priority)
{
if (grid.Priority == null)
{
grid.Priority = priority.Id;
grid.PriorityText = priority.Name;
break;
}
else if (status.Priorities.Priority.FirstOrDefault(x => x.Id == priority.Id) != null)
// You found something, do this.
}
Try it

Related

null check nested objects before using SelectMany

I have list of Countries and inside it have list of Places.
// ...
public IList<ICountriesDTO> Countries { get; set; }
public class CountriesDTO: ICountriesDTO
{
public IEnumerable<IPlacesDTO> Places { get; set;
}
I am trying to get list of Places that are not null.
allPlacesDTO.World.Countries
.SelectMany(x => x.Places == null ? null : x.Places)
.ToList();
But I receive a null exception when Places are null for their Countries object.
How can I do a null check for Places and just use return statement instead of doing select to null object, similar to what I have below?
if (allPlacesDTO.World.Countries.Places == null)
{
return;
}
Update:
My requirement was if there is no places in any of the countries just use the return statement to exit the current function without proceeding further. That was achieved by the accepted answer and Count function.
var lstAllPlaces = allPlacesDTO.World.Countries
.Where(x => x.Places != null)
.SelectMany(x => x.Places)
.ToList();
if (lstAllPlaces.Count() == 0)
{
return;
}
You can do the condition in where clause
allPlacesDTO.World.Countries.Where(x => x.Places != null)
.SelectMany(x => x.Places).ToList();
Or change the ternary operator to return new List() (it can be greedy)

How to check multiple properties on an object have the same condition?

I have a pretty long and unwieldy method which takes in an object as a parameter, then checks every property against the same criteria (== "random") and performs a specific action against the property.
public void CreateRegistration(UserGroup user, int mobileLength, int passwordLength, int questionLength) {
if (user.Title == "random") {
title.ClickDropdown();
} else {
WebElementExtensions.ClickDropdown(title,user.Title);
}
if (user.Firstname == "random") {
firstName.SendKeys(GenerateData.GenerateRandomName());
} else {
firstName.SendKeys(user.Firstname);
}
if (user.Middlename == "random") {
middleName.SendKeys(GenerateData.GenerateRandomName());
} else {
firstName.SendKeys(user.Middlename);
}
etc....
Is it possible to somehow check all my properties against the same criteria together, then reduce my code so all the actions on the individual properties are within the same code block? so one code block for is = random and one for else.
Many thanks,
I prefer to use LINQ for this purpose usually:
private bool CheckAllProperties(UserGroup instance)
{
return instance.GetType().GetProperties()
.Where(c => c.GetValue(instance) is string)
.Select(c => (string)c.GetValue(instance))
.All(c => c== "random");
}
And then:
if (CheckAllProperties(user))
{
}

How can I get an item from a generic list based on two conditions?

I have a generic list of a custom type, of which I'm trying to get back one type instance. I've tried both "FirstOrDefault" and "Where" using the two conditions which need to be true, but both of them give me the same err msg ("Operator '&&' cannot be applied to operands of type 'lambda expression' and 'lambda expression'")
Here they are:
// FirstOrDefault
UnitItemCodeItemID uicii =
unitItemCodeItemIDList
.FirstOrDefault((u => u.Unit == _unit) && (d => d.Description == desc));
// Where
UnitItemCodeItemID uicii =
unitItemCodeItemIDList
.Where((u => u.Unit == _unit) && (d => d.Description == desc));
I don't know if it's pertinent, but the class is:
public class UnitItemCodeItemID
{
public string Unit { get; set; }
public string Description { get; set; }
public string ItemCode { get; set; }
public int ItemID { get; set; }
}
You have to provide just ONE lambda:
UnitItemCodeItemID uicii = unitItemCodeItemIDList
.FirstOrDefault(obj => obj.Unit == _unit && obj.Description == desc);
Think about it this way: it's exactly like writing a foreach loop in a function. Like so:
public UnitItemCodeItemID ExtractFirst(IEnumerable<UnitItemCodeItemID> unitItemCodeItemIDList)
{
foreach(var obj in unitItemCodeItemIDList)
{
if (obj.Unit == _unit && obj.Description == desc)
return obj;
}
return null;
}
Your lamba must provide the "if" part, the rest is in the Linq implementation.
You need to provide a single lambda expression that encapsulates both conditions
.Where(p => p.Unit == _unit && p.Description == desc);
Your previous attempt was trying to combine two separate lambda expressions with an and statement.

How to check all properties of an object whether null or empty?

I have an object lets call it ObjectA
and that object has 10 properties and those are all strings.
var myObject = new {Property1="",Property2="",Property3="",Property4="",...}
is there anyway to check to see whether all these properties are null or empty?
So any built-in method that would return true or false?
If any single of them is not null or empty then the return would be false. If all of them are empty it should return true.
The idea is I do not want to write 10 if statement to control if those properties are empty or null.
Thanks
You can do it using Reflection
bool IsAnyNullOrEmpty(object myObject)
{
foreach(PropertyInfo pi in myObject.GetType().GetProperties())
{
if(pi.PropertyType == typeof(string))
{
string value = (string)pi.GetValue(myObject);
if(string.IsNullOrEmpty(value))
{
return true;
}
}
}
return false;
}
Matthew Watson suggested an alternative using LINQ:
return myObject.GetType().GetProperties()
.Where(pi => pi.PropertyType == typeof(string))
.Select(pi => (string)pi.GetValue(myObject))
.Any(value => string.IsNullOrEmpty(value));
I suppose you want to make sure that all properties are filled in.
A better option is probably by putting this validation in the constructor of your class and throw exceptions if validation fails. That way you cannot create a class that is invalid; catch exceptions and handle them accordingly.
Fluent validation is a nice framework (http://fluentvalidation.codeplex.com) for doing the validation. Example:
public class CustomerValidator: AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(customer => customer.Property1).NotNull();
RuleFor(customer => customer.Property2).NotNull();
RuleFor(customer => customer.Property3).NotNull();
}
}
public class Customer
{
public Customer(string property1, string property2, string property3)
{
Property1 = property1;
Property2 = property2;
Property3 = property3;
new CustomerValidator().ValidateAndThrow();
}
public string Property1 {get; set;}
public string Property2 {get; set;}
public string Property3 {get; set;}
}
Usage:
try
{
var customer = new Customer("string1", "string", null);
// logic here
} catch (ValidationException ex)
{
// A validation error occured
}
PS - Using reflection for this kind of thing just makes your code harder to read. Using validation as shown above makes it explicitly clear what your rules are; and you can easily extend them with other rules.
The following code returns if any property is not null.
return myObject.GetType()
.GetProperties() //get all properties on object
.Select(pi => pi.GetValue(myObject)) //get value for the property
.Any(value => value != null); // Check if one of the values is not null, if so it returns true.
Here you go
var instOfA = new ObjectA();
bool isAnyPropEmpty = instOfA.GetType().GetProperties()
.Where(p => p.GetValue(instOfA) is string) // selecting only string props
.Any(p => string.IsNullOrWhiteSpace((p.GetValue(instOfA) as string)));
and here's the class
class ObjectA
{
public string A { get; set; }
public string B { get; set; }
}
A slightly different way of expressing the linq to see if all string properties of an object are non null and non empty:
public static bool AllStringPropertyValuesAreNonEmpty(object myObject)
{
var allStringPropertyValues =
from property in myObject.GetType().GetProperties()
where property.PropertyType == typeof(string) && property.CanRead
select (string) property.GetValue(myObject);
return allStringPropertyValues.All(value => !string.IsNullOrEmpty(value));
}
Note if you've got a data structural hierarchy and you want to test everything in that hierarchy, then you can use a recursive method. Here's a quick example:
static bool AnyNullOrEmpty(object obj) {
return obj == null
|| obj.ToString() == ""
|| obj.GetType().GetProperties().Any(prop => AnyNullOrEmpty(prop.GetValue(obj)));
}
To only check if all properties are null:
bool allPropertiesNull = !myObject.GetType().GetProperties().Any(prop => prop == null);
you can use reflection and extension methods to do this.
using System.Reflection;
public static class ExtensionMethods
{
public static bool StringPropertiesEmpty(this object value)
{
foreach (PropertyInfo objProp in value.GetType().GetProperties())
{
if (objProp.CanRead)
{
object val = objProp.GetValue(value, null);
if (val.GetType() == typeof(string))
{
if (val == "" || val == null)
{
return true;
}
}
}
}
return false;
}
}
then use it on any object with string properties
test obj = new test();
if (obj.StringPropertiesEmpty() == true)
{
// some of these string properties are empty or null
}
No, I don't think there is a method to do exactly that.
You'd be best writing a simple method that takes your object and returns true or false.
Alternatively, if the properties are all the same, and you just want to parse through them and find a single null or empty, perhaps some sort of collection of strings would work for you?
You can try the following query :
if the object is "referenceKey" (where few properties may be null )
referenceKey.GetType().GetProperties().Where(x => x.GetValue(referenceKey) == null)
I need to count the properties where the value is set to not Null, so I have used the following query :
var countProvidedReferenceKeys = referenceKey.GetType().GetProperties().Where(x => x.GetValue(referenceKey) != null).Count();

how to check if List<T> element contains an item with a Particular Property Value

public class PricePublicModel
{
public PricePublicModel() { }
public int PriceGroupID { get; set; }
public double Size { get; set; }
public double Size2 { get; set; }
public int[] PrintType { get; set; }
public double[] Price { get; set; }
}
List<PricePublicModel> pricePublicList = new List<PricePublicModel>();
How to check if element of pricePublicList contains certain value. To be more precise, I want to check if there exists pricePublicModel.Size == 200? Also, if this element exists, how to know which one it is?
EDIT If Dictionary is more suitable for this then I could use Dictionary, but I would need to know how :)
If you have a list and you want to know where within the list an element exists that matches a given criteria, you can use the FindIndex instance method. Such as
int index = list.FindIndex(f => f.Bar == 17);
Where f => f.Bar == 17 is a predicate with the matching criteria.
In your case you might write
int index = pricePublicList.FindIndex(item => item.Size == 200);
if (index >= 0)
{
// element exists, do what you need
}
bool contains = pricePublicList.Any(p => p.Size == 200);
You can using the exists
if (pricePublicList.Exists(x => x.Size == 200))
{
//code
}
This is pretty easy to do using LINQ:
var match = pricePublicList.FirstOrDefault(p => p.Size == 200);
if (match == null)
{
// Element doesn't exist
}
You don't actually need LINQ for this because List<T> provides a method that does exactly what you want: Find.
Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire List<T>.
Example code:
PricePublicModel result = pricePublicList.Find(x => x.Size == 200);
var item = pricePublicList.FirstOrDefault(x => x.Size == 200);
if (item != null) {
// There exists one with size 200 and is stored in item now
}
else {
// There is no PricePublicModel with size 200
}
You can also just use List.Find():
if(pricePublicList.Find(item => item.Size == 200) != null)
{
// Item exists, do something
}
else
{
// Item does not exist, do something else
}

Categories

Resources