tags:

views:

271

answers:

3

When I call a Linq (not Linq-for-SQL, just simple in-memory Linq) - what locale it uses to compare objects, and how can I affect it?

E.g.

string[] a = { "a", "b", ... };
string max = a.Max();

What locale is used here - current, invariant? How can I affect it? The comparision seems to be case-insensitive, what if I want to find case-sensitive max?

+3  A: 

It uses the implementation of IComparable<string> in string.

You could fairly easily write your own version of Max which does take an IComparer<T> for comparisons - I'm very surprised there isn't one already. Alternatively, you could use Aggregate in a somewhat cumbersome way to accomplish the same result.

Jon Skeet
what overload? I don't see any overload of max that takes IComparer<>:http://msdn.microsoft.com/en-us/library/system.linq.enumerable.max.aspx
Michael
I do apologise - you're absolutely right. I'll edit my answer.
Jon Skeet
Yes, the Aggregate is good choice:max = files.Aggregate((a, b) => StringComparer.OrdinalIgnoreCase.Compare(a, b) < 0 ? b : a);
Michael
A: 

I decided to take a deeper look on what happening.

Max method uses Comparer class to compare items. Comparer class in turn uses GenericComparer.Compare method. This method calls String.CompareTo method. CompareTo uses following code:

CultureInfo.CurrentCulture.CompareInfo.Compare(this, strB, CompareOptions.None);

That said, you can affect behavior of Max method by changing

Thread.CurrentThread.CurrentCulture

If it's unacceptable, you have to roll out your own version of Max as Jon suggested.

aku
A: 

Posting my code based on Jon's suggestion:

static T Max<T>(this IEnumerable<T> coll, IComparer<T> comp)
{
    return coll.Aggregate((a, b) => comp.Compare(a, b) < 0 ? b : a);
}

It can be used as

string max = coll.Max(StringComparer.OrdinalIgnoreCase);
Michael