IEqualityComparer Exception with Linq (NotSupportedException) - c#

I was doing a custom Comparer to compare two classes in a Linq query like this one:
Table<Info> table = context.GetTable<Info>();
bool infoAlreadyExists = table.Contains(info, new MyComparer());
This is my comparer:
public class MyComparer : IEqualityComparer<Info>
{
#region IEqualityComparer<Info> Member
public bool Equals(Info x, Info y)
{
return x.Content == y.Content;
}
public int GetHashCode(Info obj)
{
return obj.Content.GetHashCode();
}
#endregion
}
The problem is that I get an exception. [System.NotSupportedException]
The exception tells me that a not supported overload for the Contains operator was found. Do I do something wrong or is it really NotSupported? I couldn't find anything on the documentation.
This is the definition of the overload I am trying to use of the contains method.
public static bool Contains<TSource>(this IQueryable<TSource> source, TSource item, IEqualityComparer<TSource> comparer);

That version of Contains method is not supported.You can see the full list here:
Supported and Unsupported LINQ Methods (LINQ to Entities)
So you need to perform this operation in memory, you can use AsEnumerable for that.
But in this case it seems you don't need that equality comparer. You can just use the below query to get the same result:
table.FirstOrDefault(x => x.Content == info.Content) != null;

Related

Using IEnumerable FirstOrDefault within a List extension method?

Is it possible to use IEnumerable FirstOrDefault within a List extension method? I am getting the error 'List does not contain a definition for FirstOrDefault'?
using LanguageExt;
using System;
using System.Linq;
public static class Question
{
public static Option<T> Lookup<T>(this List<T> enumerable, Func<T, bool> predicate)
{
if (enumerable == null)
{
return Option<T>.None;
}
var val = enumerable.FirstOrDefault(predicate);
return val == null ? Option<T>.None : Option<T>.Some(val);
}
public static void Run()
{
bool isOdd(int i) => i % 2 == 1;
var none = new List<int>().Lookup(isOdd); // => None
var some = new List<int> { 1 }.Lookup(isOdd); // => Some(1)
}
}
Normally it is possible to use FirstOrDefault on any enumerable sequence, so also on Lists.
The following works:
Func<int, bool> predicate = isOdd;
List<int> integerSequence = new List<int>();
var a = integerSequence.FirstOrDefault();
var b = integerSequence.Where(i => predicate(i)).FirstOrDefault();
var c = integerSequence.FirstOrDefault(i => predicate(i));
So I can't reproduce your problem. I see other problems though.
If you don't understand the this keyword, read Extension Methods demystified. Whenever you think: damn, I wish they had thought of this LINQ method, consider creating an extension method.
So your Lookup method is an extension method that takes a list and a predicate as input.. Since it seems that it can work on any enumerable sequence, let's not limit ourselves to List<T>, let's accept any enumerable sequence, like Arrays, Dictionaries, Lookup-tables, etc.
Furthermore, LINQ methods are most reusable if you let them return a sequence or result items, and let your called decide whether he wants all items, or only the FirstOrDefault, or maybe the Last, or Average.
So if you decide to create an extension method that takes an enumerable sequence as input, let it return an Enumerable sequence whenever possible, even if the sequence is empty: avoid returning null, if you mean: there are no elements matching what you want. Because that would mean that callers should have to check the result before they can continue concatenating other LINQ methods.
Finally: LINQ methods usually don't except null sources as input, they throw exceptions. LINQ methods expect callers to make sure the input is not null. Of course you are free to deviate from this, but callers don't expect it when using LINQ like methods.
With these guidelines in mind, consider to change your extension method.
Apparently, if an element in your input sequence equals null, you want to return Option<T>.None, otherwise you want Option<T>.Some(val)
public static Option<T> ToOption<T>(this T sourceElement)
{
return sourceElement?.Option<T>.Some(sourceElement) ?? Option<T>.None;
}
In words: if sourceElement equals null, return Option<T>.Some(sourceElement), otherwise return Option<T>.None
In LINQ it is quite normal to create extension methods with equality comparers, this will make your methods even more reusable. Usually this will only need two or three lines of code:
public static Option<T> ToOption<T>(this T sourceElement)
{
return ToOption(sourceElement, null);
}
public static Option<T> ToOption<T>(
this T sourceElement,
IEqualityComparer<T> comparer)
{
if (comparer == null) comparer = EqualityComparer<T>.Default;
if (comparer.Equals(sourceElement, null)
return Option<T>.None;
else
return Option<T>.Some(sourceElement);
}
In the methods below I won't mention this possibility over and over again.
public static IEnumerable<Option<T>> ToOptions<T>(this IEnumerable<T> source)
{
// TODO: throw exception if input null
return source.Select(sourceElement => sourceElement.ToOption());
}
public static IEnumerable<Option<T>> ToOptions<T>(
this IEnumerable<T> source,
Func<T, bool> predicate)
{
// No need: check if source == null, this is done in the other ToOptions
// TODO: exception if predicate equals null
return source.Where(sourceElement => predicate(sourceElement))
.ToOptions();
}
Simple usage:
IEnumerable<Customer> customers = ...
MyClass myFirstEligableCustomer= customers
.ToOptions(customer => customer.Address.City == "New York")
.FirstOrDefault();
Or intertwined with other LINQ methods:
var result = customers.
.GroupBy(customer => customer.Birthday.Year)
.OrderBy(customerGroup => customerGroup.Key)
.ToOptions(customerGroup => customerGroup.Key)
.ToDictionary(customerGroup => customerGroup.Key, // Key
customerGroup => customerGroup.ToList); // Value
The result is a Dictionary, where the key is the Year of a birthday, and the value is the list of all Option<Customer> that are born in this year.
You see: most methods are barely more than one-liners. They are easy to reuse, easy to change, easy to test.

Natural Sorting of list of string in descending order C#

I would like to ask how to sort a List<string> in descending order using the Natural Sort Comparer library.
I would like to ask if you someone have use this library
https://www.codeproject.com/Articles/22517/Natural-Sort-Comparer
to sort a List<string>?
This is the code snippets for ascending
public List<string> contents = new List<string>{ "a,b,c,d,e,f" };
public void sorting()
{
using (NaturalSortComparer comparer = new NaturalSortComparer())
{
contents.Sort(comparer);
}
}
I'm able to make it work to sort as ascending, but not descending.
Any ideas?
Let's implement a simple extension method:
public static partial class ComparerExtensions {
public static IComparer<T> Reverse<T>(this IComparer<T> comparer) {
if (null == comparer)
throw new ArgumentNullException(nameof(comparer));
return Comparer<T>.Create((left, right) => comparer.Compare(right, left));
}
}
Then you can reverse any comparer (ICompare<T>) you like:
MyList.Sort(YourCustomComparer.Reverse());
In your case (a bit strange implmentation with comparer implementing IDisposable):
using (var naturalComparer = new NaturalComparer()) {
contents.Sort(naturalComparer.Reverse());
}
Edit: In case of C# 4.0 or earlier version (which doesn't have Comparer<T>.Create) we can implement the extension method like this:
public static partial class ComparerExtensions {
private sealed class ReversedComparer<T> : IComparer<T> {
private readonly IComparer<T> m_Comparer;
public ReversedComparer(IComparer<T> comparer) {
m_Comparer = comparer;
}
public int Compare(T x, T y) {
return m_Comparer.Compare(y, x);
}
}
public static IComparer<T> Reverse<T>(this IComparer<T> comparer) {
if (null == comparer)
throw new ArgumentNullException(nameof(comparer));
return new ReversedComparer<T>(comparer);
}
}
You have two options:
Horrible, never do this: use the ascending order and then simply call Reverse() method (I'm only listing this option as a warning because, believe it or not, I've seen it more than once in production code).
The good way: Implement an IComparer<string> that simply returns the negative of the "ascending" comparer (or switches the argument order) and pass it into your sorting method.
But nÂș2 is already built in the framework for you; its the extension method OrderByDescending:
var ss = new[] {"a1", "a03", ... }
var descending = ss.OrderByDescending(
s => s,
new NaturalComparer());
UPDATE: Your updated question seems to imply you want to use List.Sort. In that case the way to go is #2, OrderBy will not sort in place.

Dynamic LINQ Method to return List of different Items from two lists

I want to write dynamic LINQ function to return the different between two lists but in abstraction way to make this function take any two lists of the same type and return the items that is the first list but not in the second one
I write some thing like the below and it is working fine but as I mention above I need it in abstraction way
List<Employee> a = List of Items;
List<Employee> b = List of Items;
var finalCountries = a.Where(u => !b.Any(u2 => u2.ISOA2 == u.ISOA2)).ToList();
I read about dynamic LINQ expression but it is complex and I have no luck to find what I am looking to
if there are any way to write the above where statement as string and execute it?
You can use Enumerable.Except like this
List<Employee> a;
List<Employee> b;
var finalCountries = a.Except(b).ToList();
If you need to compare your Employees by some field and this is not implemented by Employee you can use a custom comparer. For example this one. When your code can look like:
var comparer = new LambdaComparer<Employee>((emp1,emp2)=>emp1.ISOA2 == emp2.ISOA2);
var finalCountries = a.Except(b,comparer).ToList();
LambdaComparer code for convenience:
class LambdaComparer<T> : IEqualityComparer<T>
{
readonly Func<T, T, bool> _lambdaComparer;
readonly Func<T, int> _lambdaHash;
public LambdaComparer(Func<T, T, bool> lambdaComparer) :
this(lambdaComparer, o => 0){}
public LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
{
_lambdaComparer = lambdaComparer ?? throw new ArgumentNullException(nameof(lambdaComparer));
_lambdaHash = lambdaHash ?? throw new ArgumentNullException(nameof(lambdaHash));
}
public bool Equals(T x, T y) => _lambdaComparer(x, y);
public int GetHashCode(T obj) => _lambdaHash(obj);
}
update:
To make your method generic you can implement IEquatable interface in each of your entity types and use Except overload without parameters.

Remove Duplicates From List<T> Based on Property Selected By Lambda

I've a List<User> which have several keys. I have several scenarios. In some cases I want to remove duplicates based on Key1 and in other based on Key2. Both properties on the User object.
I thought this would be as simple as to give the Distinct function a generic IEqualityComparer like this:
public class AwesomeEqualityComparerOfDoom<T> : IEqualityComparer<T> where T : class
{
private readonly Func<T, object> compiledFunction;
public AwesomeEqualityComparerOfDoom(Func<T, object > propertyFunction)
{
compiledFunction = propertyFunction;
}
public bool Equals(T x, T y)
{
object key1 = compiledFunction(x);
object key2 = compiledFunction(y);
return key1.Equals(key2);
}
public int GetHashCode(T obj)
{
return obj.GetHashCode();
}
}
When I test this class manually by creating an instance of it, and giving it two users with the same key, then it works. However, when I pass it off to the Distinct function no users are removed as being duplicates.
I also tried making the IEquality class be defined as AwesomeEqualityComparerOfDoom<T,TT>, so it knew what kind of value it would be calling Equals on but to no avail.
You're not using the compiledFunction in your GetHashCode implementation - you're just using the hash code of the item itself. You want something like:
public int GetHashCode(T obj)
{
return compiledFunction(obj).GetHashCode();
}
However:
You should consider making your class generic in the projected type as well, taking (say) Func<TElement, TKey> instead of just Func<T, object>
You should consider using EqualityComparer<TKey> to handle null keys.
I have classes which help with this already in MiscUtil with helper methods so you can do things like this:
var comparer = ProjectionEqualityComparer<User>.Create(x => x.Name);
The key type is then inferred from the lambda expression.
Distinct() is a LINQ method that returns a new sequence without any duplicates.
It doesn't modify the original list.

In LINQ, select all values of property X where X != null

Is there a shorter way to write the following? (Something that would check for null without explicitly writing != null)
from item in list
where item.MyProperty != null
select item.MyProperty
You can use the OfType operator. It ignores null values in the source sequence. Just use the same type as MyProperty and it won't filter out anything else.
// given:
// public T MyProperty { get; }
var nonNullItems = list.Select(x => x.MyProperty).OfType<T>();
I would advise against this though. If you want to pick non-null values, what can be more explicit than saying you want "the MyProperties from the list that are not null"?
You could define your own extension method, but I wouldn't recommend that.
public static IEnumerable<TResult> SelectNonNull<T, TResult>(this IEnumerable<T> sequence,Func<T, TResult> projection)
{
return sequence.Select(projection).Where(e => e != null);
}
I don't like this one because it mixes two concerns. Projecting with Select and filtering your null values are separate operations and should not be combined into one method.
I'd rather define an extension method that only checks if the item isn't null:
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T> sequence)
{
return sequence.Where(e => e != null);
}
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> sequence)
where T : struct
{
return sequence.Where(e => e != null).Select(e => e.Value);
}
This has only a single purpose, checking for null. For nullable value types it converts to the non nullable equivalent, since it's useless to preserve the nullable wrapper for values which cannot be null.
With this method, your code becomes:
list.Select(item => item.MyProperty).WhereNotNull()
I tend to create a static class containing basic functions for cases like these. They allow me write expressions like
var myValues myItems.Select(x => x.Value).Where(Predicates.IsNotNull);
And the collection of predicate functions:
public static class Predicates
{
public static bool IsNull<T>(T value) where T : class
{
return value == null;
}
public static bool IsNotNull<T>(T value) where T : class
{
return value != null;
}
public static bool IsNull<T>(T? nullableValue) where T : struct
{
return !nullableValue.HasValue;
}
public static bool IsNotNull<T>(T? nullableValue) where T : struct
{
return nullableValue.HasValue;
}
public static bool HasValue<T>(T? nullableValue) where T : struct
{
return nullableValue.HasValue;
}
public static bool HasNoValue<T>(T? nullableValue) where T : struct
{
return !nullableValue.HasValue;
}
}
There is no way to skip a check if it exists.
// if you need to check if all items' MyProperty doesn't have null
if (list.All(x => x.MyProperty != null))
// do something
// or if you need to check if at least one items' property has doesn't have null
if (list.Any(x => x.MyProperty != null))
// do something
But you always have to check for null
get one column in the distinct select and ignore null values:
var items = db.table.Where(p => p.id!=null).GroupBy(p => p.id)
.Select(grp => grp.First().id)
.ToList();
This is adapted from CodesInChaos's extension method. The name is shorter (NotNull) and more importantly, restricts the type (T) to reference types with where T : class.
public static IEnumerable<T> NotNull<T>(this IEnumerable<T> source) where T : class
{
return source.Where(item => item != null);
}
I know i am a bit late to the party but I found a IMO very elegant sollution to this problem. I wrote an extension method to chain onto my LINQ queries:
public static IEnumerable<T> DiscardNullValues<T>(this IEnumerable<T?> nullable)
{
foreach (var item in nullable)
{
if (item is not null) yield return item;
}
}
Works like a charm.
This is a feature that have been proposed to the dotnet/runtime issue tracker.
See this comment that proposes a SelectNotNull function :
https://github.com/dotnet/runtime/issues/30381#issuecomment-806396119

Categories

Resources