あなたが望むことを行うための組み込みの比較方法はありませんが、それはあなたが話している「長ったらしい」部分ではないと思います。
煩わしいのは、単純な比較関数であるべきものを渡すためだけにカスタム比較クラスを作成しなければならないことです。
さて、それを軽減する方法があります。メソッドの名前を渡すだけで OrderBy() を使用できるいくつかのヘルパー クラスを作成できます。これらのクラスを作成すると、すべての OrderBy() ステートメントで機能します。
ここにいくつかのサンプルコードがあります。ヘルパー クラスは、EnumerableExt および ComparisonDelegator と呼ばれます。これらは連携して、メソッドを OrderBy() に渡すことができます。
以下のコードは明らかにあなたのコードよりもはるかに長いですが、EnumerableExt クラスと ComparisonDelegator クラスは別の共通アセンブリにあるので、それらを数えないでください。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
namespace Demo
{
public static class Program
{
private static void Main(string[] args)
{
var unorderered = new[] { "a", "b", "c", "x", "y", "z" };
var ordered = unorderered.OrderBy(compare); // Just need to specify the compare method!
}
// Each custom compare method must be written specially, as before:
private static int compare(string x, string y)
{
if (x == y)
return 0;
else
{
//----------------------------
//beginning of custom ordering
var customPriority = new[] { "y", "x" };
if (customPriority.Any(a => a == x) && customPriority.Any(a => a == y)) //both in custom ordered array
{
if (Array.IndexOf(customPriority, x) < Array.IndexOf(customPriority, y))
return -1;
return 1;
}
else if (customPriority.Any(a => a == x)) //only one item in custom ordered array (and its x)
return -1;
else if (customPriority.Any(a => a == y)) //only one item in custom ordered array (and its y)
return 1;
//---------------------------
//degrade to default ordering
else
return string.Compare(x, y);
}
}
}
// The following classes only need to be written once:
public static class EnumerableExt
{
/// <summary>
/// Convenience method on IEnumerable{T} to allow passing of a
/// Comparison{T} delegate to the OrderBy method.
/// </summary>
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, Comparison<T> comparison)
{
Contract.Requires(list != null, "list can't be null.");
Contract.Requires(comparison != null, "comparer can't be null.");
return list.OrderBy(t => t, new ComparisonDelegator<T>(comparison));
}
}
/// <summary>
/// Provides a mechanism for easily converting a Comparison<> delegate (or lambda) to an IComparer<>.
/// This can be used for List.BinarySearch(), for example.
/// </summary>
/// <typeparam name="T">The type of items to be compared.</typeparam>
public sealed class ComparisonDelegator<T>: IComparer<T>, IComparer
{
/// <summary>Create from a Comparison<> delegate.</summary>
/// <param name="comparison">A Comparison<> delegate.</param>
public ComparisonDelegator(Comparison<T> comparison)
{
Contract.Requires(comparison != null);
this._comparison = comparison;
}
/// <summary>Implements the IComparer.Compare() method.</summary>
public int Compare(T x, T y)
{
return _comparison(x, y);
}
/// <summary>Implements the IComparer.Compare() method.</summary>
public int Compare(object x, object y)
{
return _comparison((T)x, (T)y);
}
/// <summary>Used to store the Comparison delegate.</summary>
private readonly Comparison<T> _comparison;
}
}
次に、次のように比較メソッドをインラインで記述することもできます (ただし、このような複雑な比較メソッドについてはお勧めしません。これは説明のためだけです)。
private static void Main(string[] args)
{
var unorderered = new[] { "a", "b", "c", "x", "y", "z" };
var ordered = unorderered.OrderBy((x, y) =>
{
if (x == y)
return 0;
else
{
var customPriority = new[] { "y", "x" };
if (customPriority.Any(a => a == x) && customPriority.Any(a => a == y)) //both in custom ordered array
{
if (Array.IndexOf(customPriority, x) < Array.IndexOf(customPriority, y))
return -1;
return 1;
}
else if (customPriority.Any(a => a == x)) //only one item in custom ordered array (and its x)
return -1;
else if (customPriority.Any(a => a == y)) //only one item in custom ordered array (and its y)
return 1;
else
return string.Compare(x, y);
}
});
}