LINQ new instance when SingleOrDefault returns null - c#

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

Related

default(T) is null when T is a List

Given the following function:
public static T GetCachedBoxedValue<T>(string cacheKey, Func<T> getFromExternFunction, bool skipLocalCaches = false)
{
var r = Manager.Get(
cacheKey,
() => new Tuple<T>(
getFromExternFunction()
),
skipLocalCaches
);
if (r == null || r.Item1 == null)
{
return default;
}
return r.Item1;
}
When T is a List<Guid> and the r value is null, it returns null. How would I modify this to return a new empty list?
You can add the new constraint to the method and call new T():
public static T GetCachedBoxedValue<T>(string cacheKey, Func<T> getFromExternFunction, bool skipLocalCaches = false)
where T:new()
{
...
if (r == null || r.Item1 == null)
{
return new T();
}
return r.Item1;
}
The new constraint tells the debugger that only types that have a parameterless constructor can be used, allowing you to call it.
The default value for all reference types is null. An empty List on the other hand is a fully constructed List instance. For more information about default values see: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/default-values

How return IEnumerable<T>/IList<T> is null or value using null-coalescing operator

I want to use the null-coalescing operator with three Statements.
If the first list returns null then return the second list
If second list returns null then return the third list
private IList<a> a => new IList<a>().ToList();
private IList<a> CalcDate
{
get
{
return a.Where(p => p.a.LastDate.HasValue && p.a.LastDateHasValue <= DateTime.Today)
?? a.Where(p => p.LastUpdateDate.HasValue && p.LastUpdateDate <= DateTime.Today)
?? a.Where(p => p.CreateDate.HasValue && p.CreateDate <= DateTime.Today);
}
}
I don't want to use ?: operator, because I want to keep the code short.
Please help me with ideas for short and readable code and more tips
You can add your own extension method called NullIfEmpty like following
public static class Extensions
{
public static IEnumerable<T> NullIfEmpty<T>(this IEnumerable<T> seq)
{
if (!seq.Any())
return null;
return seq;
}
}
And then you can use this method somewhat like this:
return a.Where(...).NullIfEmpty()
?? a.Where(...).NullIfEmpty()
?? a.Where(...);

Check List<T> for duplications with optional words to exclude

I have a method as below. Method return either false/true either when list contains duplicates or not. I would like to extend my method to say for instance (optional) that i want to exclude specific items from check. For instance i want to check entire list as it is now or i want to say for instance exclude: string.empty items or for instance string.empty and "some word". Is it possible?
public static bool IsListContainsDuplicates<T>(List<T> list)
{
return list.GroupBy(n => n).Any(c => c.Count() > 1);
}
public static bool ContainsDuplicates<T>(this IEnumerable<T> items, IEnumerable<T> itemsToExclude = null)
{
if (itemsToExclude == null) itemsToExclude = Enumerable.Empty<T>();
return items.Except(itemsToExclude)
.GroupBy(n => n)
.Any(c => c.Count() > 1);
}
But i'd prefer this implementation because it's more performant:
public static bool ContainsDuplicates<T>(this IEnumerable<T> items, IEnumerable<T> itemsToExclude = null)
{
if (itemsToExclude == null) itemsToExclude = Enumerable.Empty<T>();
HashSet<T> set = new HashSet<T>();
return !items.Except(itemsToExclude).All(set.Add);
}
Instead of making your method more complicated, you should open it more to combine it with others:
public static class MyLinqMethods
{
public static bool HasDuplicates<T>(this IEnumerable<T> sequence)
{
return sequence.GroupBy(n => n).Any(c => c.Count() > 1);
}
}
Now you can use it with Linq:
var original = new[] { string.Empty, "Hello", "World", string.Empty };
var duplicatesInOriginal = original.HasDuplicates();
var duplicatesIfStringEmptyIsIgnored = original.Where(o => o != string.Empty).HasDuplicates();
You can use Except(). From MSDN:
Produces the set difference of two sequences by using the default
equality comparer to compare values.
return list.Except(listToExclude).GroupBy(n => n).Any(c => c.Count() > 1);
This will also help, using a 'params' in arguments and then doing Except()
public static bool IsListContainsDuplicates<T>(List<T> list, params T[] optional)
{
return list.Except(optional).GroupBy(n => n).Any(c => c.Count() > 1);
}
You can call like this if you doesn't want to exclude anything:
IsListContainsDuplicates(list)
Else, just pass the params values, for example, if the list is an integer list then,
IsListContainsDuplicates(list,5,4)

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

How to write boolean function in a single line in C#?

public bool IsNewUser(int id)
{
var data= DataContext.Employee.Where(e=>e.id==id).FirstorDefault();
if(data==null)
return true;
return false;
}
How can I write the above function logic using maybe ?? or something else in a single line in C#? I am sure that must be possible just can't think right now..Thanks
This wouldn't be a case to use ?? but this should help:
public bool IsNewUser(int id)
{
return !DataContext.Employee.Any(e => e.id == id);
}
?? would be used doing something like this:
public Employee GetEmployeeOrNew(int id)
{
return DataContext.Employee.Where(e => e.id == id).FirstorDefault() ?? new Employee();
}
return (null == DataContext.Employee.Where(e=>e.id==id).FirstorDefault());
The Any operator would be more appropriate than FirstOrDefault:
public bool IsNewUser(int id)
{
return !DataContext.Employee.Any(e => e.id == id);
}
return DataContext.Employee.Where(e=>e.id==id).FirstorDefault() == null;
?? is the null coalescing operator, used to assign a default value instead of null. IE
data = data ?? GetNonNullData();
?: is the ternary conditional, probably what you were thinking of. But it's not actually necessary in this case.
You should use the Any method instead of the Where...FirstOrDefault construct:
public bool IsNewUser(int id)
{
return !DataContext.Employee.Any(e=>e.id==id);
}
return !DataContext.Employee.Any(e=>e.id==id);
return data == null ? true : false;
return DataContext.Employee.Any(e => e.id == id);

Categories

Resources