лично я бы избежал короткого замыкания от операторов и просто позволил бы методам связать его:
public static int CompareChain<T>(this int previous, T a, T b)
{
if (previous != 0)
return previous;
return Comparer<T>.Default.Compare(a,b);
}
используйте так:
int a = 0, b = 2;
string x = "foo", y = "bar";
return a.Compare(b).CompareChain(x,y);
может быть встроен в JIT, поэтому он может выполнять такие же короткие замыкания, что и встроенный в язык, без лишних сложностей.
В ответ на ваш вопрос, может ли указанная выше «структура» применяться не только к сравнениям, но да, это может быть сделано путем выбора: продолжать или нет объяснять и контролировать пользователь. Это по своей сути более сложное, но операция более гибкая, поэтому это неизбежно.
public static T ElseIf<T>(
this T previous,
Func<T,bool> isOK
Func<T> candidate)
{
if (previous != null && isOK(previous))
return previous;
return candidate();
}
затем используйте так
Connection bestConnection = server1.GetConnection()
.ElseIf(IsOk, server2.GetConnection)
.ElseIf(IsOk, server3.GetConnection)
.ElseIf(IsOk, () => null);
Это максимальная гибкость, поскольку вы можете изменить проверку IsOk на любом этапе и быть полностью ленивыми. Для ситуаций, когда проверка «ОК» одинакова в каждом случае, вы можете упростить, как и так, и полностью избежать методов расширений.
public static T ElseIf<T>(
Func<T,bool> isOK
IEnumerable<Func<T>[] candidates)
{
foreach (var candidate in candidates)
{
var t = candidate();
if (isOK(t))
return t;
}
throw new ArgumentException("none were acceptable");
}
Вы можете сделать это с помощью linq, но этот способ выдает красивое сообщение об ошибке и позволяет это
public static T ElseIf<T>(
Func<T,bool> isOK
params Func<T>[] candidates)
{
return ElseIf<T>(isOK, (IEnumerable<Func<T>>)candidates);
}
стиль, который приводит к хорошему читабельному коду, например:
var bestConnection = ElseIf(IsOk,
server1.GetConnection,
server2.GetConnection,
server3.GetConnection);
Если вы хотите разрешить значение по умолчанию, то:
public static T ElseIfOrDefault<T>(
Func<T,bool> isOK
IEnumerable<Func<T>>[] candidates)
{
foreach (var candidate in candidates)
{
var t = candidate();
if (isOK(t))
return t;
}
return default(T);
}
Очевидно, что все вышеперечисленное можно очень легко написать с помощью лямбд, поэтому ваш конкретный пример будет:
var bestConnection = ElseIfOrDefault(
c => c != null && !(c.IsBusy || c.IsFull),
server1.GetConnection,
server2.GetConnection,
server3.GetConnection);