Embed a test for null in a single LINQ expression - c#

Let's start with a simple example class:
public class Foo
{
public DateTime Date { get; set; }
public decimal Price { get; set; }
}
Then create a list:
List<Foo> foos = new List<Foo>;
I would like to return a formatted price or "N/A" of one item in the list based on a date, so for example I could write:
Foo foo = foos.FirstOrDefault(f => f.Date == DateTime.Today);
string s = (foo != null) ? foo.Price.ToString("0.00") : "N/A";
I would like to combine the above 2 lines like the following:
string s = foos.FirstOrDefault(f => f.Date == DateTime.Today).Price.ToString("0.00") ?? "N/A";
However, this does not achieve what I want because if (f => f.Date == DateTime.Today) does not return a Foo then a NullReferenceException is thrown.
Therefore, is it possible with LINQ to create just 1 statement to either return the formatted price or "N/A"?

If you filter first and then select, you can use the null coalescing operator (??) like so:
string price = foos.Where(f => f.Date == DateTime.Today)
.Select(f => f.Price.ToString())
.FirstOrDefault() ?? "N/A";

One way would be to simply check if result of FirstOrDefault is null, before calling ToString:
var todayFoo = foos.FirstOrDefault(f => f.Date == DateTime.Today);
var s = todayFoo != null ? todayFoo.Price.ToString("0.00") : "N/A";
Another way would be to create an extension method for a coalescing operator which also accepts a projection delegate, something like:
public static class ObjectExt
{
public static T2 Coalesce<T1, T2>(
this T1 obj, Func<T1, T2> projection, T2 defaultValue)
{
if (obj == null)
return defaultValue;
return projection(obj);
}
}
And then call it like this:
var s = foos
.FirstOrDefault(f => f.Date == DateTime.Today)
.Coalesce(t => t.Price.ToString("0.00"), "N/A");

string s = foos.Where(f => f.Date == DateTime.Today).Select(f => f.Price.ToString("0.00")).FirstOrDefault();

Related

LINQ where condition with dynamic column

I have this code
// IQueryable<General> query
if (columnName == "Column1")
{
query = query.Where(x => x.Column1 == searchValue);
}
else if (columnName == "Column2")
{
query = query.Where(x => x.Column2 == searchValue);
}
else if (columnName == "Column3")
{
query = query.Where(x => x.Column3 == searchValue);
}
else if (columnName == "Column4")
{
query = query.Where(x => x.Column4 == searchValue);
}
// next zilions columns to come
// ...
and my question is. How can i past x.Column as a parameter inside ".Where" condition ?
You can create a predicate manually. Use this method:
public static Expression<Func<General, bool>> CreatePredicate(string columnName, object searchValue)
{
var xType = typeof(General);
var x = Expression.Parameter(xType, "x");
var column = xType.GetProperties().FirstOrDefault(p => p.Name == columnName);
var body = column == null
? (Expression) Expression.Constant(true)
: Expression.Equal(
Expression.PropertyOrField(x, columnName),
Expression.Constant(searchValue));
return Expression.Lambda<Func<General, bool>>(body, x);
}
Now you can apply your predicate:
IQueryable<General> query = //
var predicate = CreatePredicate(columnName , searchValue);
query = query.Where(predicate);
You could use reflection and extension methods. As a rough example:
public class Foo
{
public int Column1 { get; set; }
public int Column2 { get; set; }
...
}
public static class FooExtensions
{
// I would use the actual type here instead of object if you know the type.
public static object GetProperyValue(this Foo foo, string columnName)
{
var propertyInfo = foo.GetType().GetProperty(columnName);
var value = propertyInfo.GetValue(foo);
// as well as cast value to the type
return value;
}
}
...
query = query.Where(x => x.GetProperyValue(columnName) == searchValue);
...
As a side note, that is not a well-designed query because every time you add a column to your model, you'd need to update your if-else. It violates the O in SOLID.
You can either use Reflection to retrieve the property via name
x.GetType().GetProperty(propertyName,BindingFlags).SetValue(x,value)
// propertyName = "Column1" for example
// BindingFlags are most likely Instance, Public and Property (IIRC)
or pass in the PropertyInfo directly into the method as a parameter. Your choice depends on the abstraction level you want to expose to consumers of your method.

C# - Getting all enums value by attribute

I have this following enum :
public enum KodEnum
{
[EnumType(EnumType = "Task")]
TaskTab,
[EnumType(EnumType = "Task")]
TaskReason,
[EnumType(EnumType = "Action")]
ActionTab,
[EnumType(EnumType = "Action")]
ActionReason
}
public class EnumTypeAttribute : Attribute
{
public string EnumType { get; set; }
}
And I want to get a list of all the enums that have the EnumType of "Task".
How could I do that?
Something like this should get you on the way...
var enumValues = (from member in typeof(KodEnum).GetFields()
let att = member.GetCustomAttributes(false)
.OfType<EnumTypeAttribute>()
.FirstOrDefault()
where att != null && att.EnumType == "Task"
select member.GetValue(null))
.Cast<KodEnum>()
.ToList();
If you want the int value, then just cast it:
var enumValues = (from member in typeof(KodEnum).GetFields()
let att = member.GetCustomAttributes(false)
.OfType<EnumTypeAttribute>()
.FirstOrDefault()
where att != null && att.EnumType == "Task"
select (int)member.GetValue(null))
.ToList();
And all-lambda solution:
var enumValues = typeof(KodEnum)
.GetFields()
.Select(x => new
{
att = x.GetCustomAttributes(false)
.OfType<EnumTypeAttribute>()
.FirstOrDefault(),
member = x
})
.Where(x => x.att != null && x.att.EnumType == "Task")
.Select(x => (int)x.member.GetValue(null))
.ToList();
You can do it like:
var result = Enum.GetValues(typeof(KodEnum)).OfType<KodEnum>()
.Where(x=>x.EnumType() == "Task");
here is EnumType extension method implementation:
public static class EnumExtensions
{
public static string EnumType(this Enum value)
{
FieldInfo field = value.GetType().GetField(value.ToString());
EnumTypeAttribute attribute
= Attribute.GetCustomAttribute(field, typeof(EnumTypeAttribute ))
as EnumTypeAttribute;
return attribute == null ? value.ToString() : attribute.EnumType ;
}
}
Keyword is Reflection:
Have you tried something like this?
Enum.GetValues(typeof(KodEnum))
.OfType<KodEnum>()
.Where(o => o.GetType()
.GetCustomAttributes(typeof(EnumTypeAttribute), false)
.OfType<EnumTypeAttribute>()
.FirstOrDefault()
.EnumType == "Task");

Pass orderBy or OrderByDescending as parameter

I have method like this :
GetUsallyOpeningClosingHour(Func<OpeningDay, TimeSpan> groupByRule)
{
var openingClosingHours = listOfSpecificDayOfWeek.GroupBy(groupByRule).OrderByDescending(x => x.Key);
}
and the problem is that I can't stick all the time with OrderByDescending depends on groupByRule parameter sometimes it has to be orderByDescending or OrderBy
I don't want to depend on this parameter, so I could pass another one for that,
Right now I call my method this way:
GetUsallyOpeningClosingHour(x => x.From)
or
GetUsallyOpeningClosingHour(x => x.To)
How can I pass orderBy type as well ?
The simplest way is adding a parameter, which will specify an order in your collection.
public void GetUsallyOpeningClosingHour(
Func<OpeningDay, TimeSpan> groupByRule,
bool orderByDesc = false)
{
var groupedDays = listOfSpecificDayOfWeek.GroupBy(groupByRule);
var openingClosingHours =
orderByDesc
? groupedDays.OrderByDescending(x => x.Key)
: groupedDays.OrderBy(x => x.Key);
}
It could be a boolean or custom enum (I prefer enum, because it actually specifies a kind of ordering operation, while boolean specifies whether collection should be ordered by desc or not).
public enum OrderingType
{
Ascending,
Descending,
None
}
Or you could provide an additional Func, which will perform an ordering operation. But its signature will be awkward.
public static void GetUsallyOpeningClosingHour(
Func<OpeningDay, TimeSpan> groupByRule,
Func<IEnumerable<IGrouping<TimeSpan, OpeningDay>>,
IEnumerable<IGrouping<TimeSpan, OpeningDay>>> orderBy)
{
var groupedDays = listOfSpecificDayOfWeek.GroupBy(groupByRule);
var openingClosingHours = orderBy(groupedDays);
}
I guess you could create your own OrderBy extension that let you select ascending/descending based on a parameter.
Something like this:
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
bool descending
)
{
return descending ? source.OrderByDescending(keySelector)
: source.OrderBy(keySelector);
}
You can also use an enum instead of the boolean to make things more readable when calling this method.
This is the most direct way to parameterise for OrderBy and OrderByDescending. Fortunately the type can be inferred for you by Visual Studio; unfortunately the type is long to write out. I added the static void and the initializer for listOfSpecificDayOfWeek so that this is easy to paste into a program for testing.
static void GetUsallyOpeningClosingHour(
Func<OpeningDay, TimeSpan> groupByRule,
Func<IEnumerable<IGrouping<TimeSpan, OpeningDay>>,
Func<IGrouping<TimeSpan, OpeningDay>, TimeSpan>,
IOrderedEnumerable<IGrouping<TimeSpan, OpeningDay>>> order)
{
IEnumerable<OpeningDay> listOfSpecificDayOfWeek = null;
var openingClosingHours = order(listOfSpecificDayOfWeek.GroupBy(groupByRule), x => x.Key);
}
You can call this function like this:
GetUsallyOpeningClosingHour(x => x.From, Enumerable.OrderByDescending);
GetUsallyOpeningClosingHour(x => x.From, Enumerable.OrderBy);
As other answers indicate, you can also just use a boolean flag to indicate ascending or descending order.
You would have to pass in a parameter as there's no way for the method to know which direction you want to sort in based only on the parameter (eg. From/To).
public [return-type] GetUsallyOpeningClosingHour(Func<OpeningDay, TimeSpan> groupByRule, bool isAscending)
{
var openingClosingHours = listOfSpecificDayOfWeek.GroupBy(groupByRule);
if (isAscending)
{
openingClosingHours = openingClosingHours.OrderBy(x => x.Key);
}
else
{
openingClosingHours = openingClosingHours.OrderByDescending(x => x.Key);
}
// Return openingClosingHours? It's not clear how you're using this variable.
}
public List<Book> Books(string orderField, bool desc, int skip, int take)
{
var propertyInfo = typeof(Book).GetProperty(orderField);
return _context.Books
.Where(...)
.OrderBy(p => !desc ? propertyInfo.GetValue(p, null) : 0)
.ThenByDescending(p => desc ? propertyInfo.GetValue(p, null) : 0)
.Skip(skip)
.Take(take)
.ToList();
}
this is my code sample:
public IQueryable<T> GetAllbySearch(
int pageNumber = 1, int pageSize = 10,
Dictionary<string, dynamic> filterParams = null,
Func<IQueryable<T>, IIncludableQueryable<T, object>> include = null,
bool allIncluded = false
, Func<IQueryable<T>, IOrderedQueryable<T>> order = null)
{
var query = _entity.AsQueryable();
if (include != null && !allIncluded)
{
query = include(query);
}
if (allIncluded && include == null)
{
foreach (var property in _context.Model.FindEntityType(typeof(T)).GetNavigations()
.Where(r => !r.IsCollection()))
query = query.Include(property.Name);
}
if (filterParams != null && filterParams.Any())
{
if (filterParams.Any(r => r.Value != null))
{
var expression = GetSearchFilter(filterParams);
if (order != null)
{
return order(query.Where(expression));
}
else
{
return query.Where(expression));
}
}
}
if (order != null)
{
return order(query);
}
else
{
return query;
}
}

Fluent NHibernate Where on Empty String

I'm applying a .Where()-restriction on an IQueryOver<T,T> in FluentNH, as such:
.Where(x => x.Col1 == null || x.Col1 == "");
Which generates the following SQL:
WHERE (Col1 IS NULL OR Col1 = NULL)
How can I make NH understand that empty string means empty string?
You can write your Where clause like this:
.Where(Restrictions.On<ClassType>(obj => obj.Col1).IsNull ||
Restrictions.On<ClassType>(obj => obj.Col1).IsLike(#""))
Alternatively, if you're doing this on several queries you should consider creating a query extension:
public static class QueryExtention {
public static IQueryOver<E, F> WhereStringIsNullOrEmpty<E, F>(this IQueryOver<E, F> query, Expression<Func<E, object>> expression) {
var property = Projections.Property(expression);
var criteria = Restrictions.Or(Restrictions.IsNull(property),
Restrictions.Eq(property, string.Empty));
return query.Where(criteria);
}
}
Then you should be able to create something like:
.QueryOver<ClassType>()
.WhereStringIsNullOrEmpty(obj => obj.Col1)

LINQ new instance when SingleOrDefault returns null

I have this simple method:
#region Fields
private Collection<Address> _addresses;
#endregion
#region Public methods
public Address DeliveryAddress()
{
if (_addresses == null)
if (this.Id > 0)
_addresses = Core.Data.Addresses.GetClient(this.Id);
return _addresses.SingleOrDefault(x => x.TypeId == AddressType.Delivery);
}
public Address InvoiceAddress()
{
if (_addresses == null)
if (this.Id > 0)
_addresses = Core.Data.Addresses.GetClient(this.Id);
return _addresses.SingleOrDefault(x => x.TypeId == AddressType.Invoice);
}
#endregion
As you can see I trying to return one result for a DeliveryAddress and one result for an InvoiceAddress. My problem is that I would like the link expression to create a new instance of Address() if SingleOrDefault returns null.
I am really new to linq, so I am not sure whether SingleOrDefault is the correct expression I should be using.
You could use DefaultIfEmpty and use that instance as default value:
return _addresses.Where(x => x.TypeId == AddressType.Delivery)
.DefaultIfEmpty(new Adress())
.Single();
Use the null-coalescing operator:
return _addresses
.SingleOrDefault(x => x.TypeId == AddressType.Delivery) ?? new Address();
The expression
x ?? y
yields x if x is not null, otherwise y. You can chain the operator
x ?? y ?? z ?? t
This returns the first non-null value or null if all of them are null.
UPDATE
Note that SingleOrDefault throws an exception if the sequence has more than one element. If you need the first element of a sequence possibly having no or more than one element, use FirstOrDefault instead.
You could create your own extension method, like this:
public static T NewIfNull<T>(this T obj) where T: class, new()
{
return obj ?? new T();
}
... then tack a usage onto the end of SingleOrDefault:
var singleResult = myCollection.SingleOrDefault().NewIfNull();
... or because the logic is so simple, just inline it as other answers have said.
Instead of
return _addresses.SingleOrDefault(x => x.TypeId == AddressType.Delivery);
Do something like this:
var address = _addresses.SingleOrDefault(x => x.TypeId == AddressType.Delivery);
if(address == null)
address = new Address();
return address;
I'd be inclined to write both of these as extension methods on IEnumerable<Address>. You can use the null-coalesing operator to return a new instance if the SingleOrDefault() call returns null.
public static class AddressExtensions
{
public static Address DeliveryAddress(this IEnumerable<Address> addresses)
{
return addresses.SingleOrDefault(x => x.TypeId == AddressType.Delivery)
?? new Address();
}
public static Address InvoiceAddress(this IEnumerable<Address> addresses)
{
return addresses.SingleOrDefault(x => x.TypeId == AddressType.Invoice)
?? new Address();
}
}
Apart from alternatives in other answers, you can also create your own SingleOrNew Extension method.
public static TSource SingleOrNew<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate ) where T:new()
{
return source.SingleOrDefault(predicate) ?? new T();
}
It can be used as
return _addresses.SingleOrNew(x => x.TypeId == AddressType.Delivery);

Categories

Resources