패턴매칭이나 bool TryGet...(key, out value) 패턴은 절차적인 영역에서는 접근과 분기를 한번에 우아하게 구사할수 있지만
Linq문법이나 람다식가지고는 컴파일검증을 확실히 도움받으면서 한번에 이어붙이기가 어려움.
말하자면 한번의 표현으로 Select를 하는 동시에 Where을 걸어줄수있는 방법이 필요함.
그리하여 Select(i=>When(... 이란 패턴에 도달하기까지의 과정임.
이부분을 하도 잡스럽게 오래 알아봐서 더이상 개연성 있는 스토리텔링도 못하겠고 그냥 삽질코드 기록임.
Unsafe클래스로 합법적으로 사기쳐서 타입추론과 조건결과, 값반환을 통합시킴.
튜플은 우연찮게 사용하게될 여지가 있으므로 이전처럼 유니크한 타입에 의존시키는게 나을수도?
그 명명된 타입의 이름을 뭐라고 정할지가 최대난관임.
이하 대충 복붙용
delegate bool Func1<in T, TResult>(T t_in, out TResult t_out);
static IEnumerable<TResult> SelectWhen1<T, TResult>(this IEnumerable<T> e, Func1<T, TResult> f)
{
foreach (var i in e)
if (f(i, out var o))
yield return o;
}
new[] {new{}, null, new{}}.SelectWhen1((object i, out object o) => { if(i is {} oo) o = oo; else o = default; }).Display();
static IEnumerable<TResult> SelectWhen2<T, TResult>(this IEnumerable<T> e, Func<T, (bool, TResult)> f)
{
foreach (var i in e)
if (f(i) is (true, var o))
yield return o;
}
static IEnumerable<TResult> SelectWhen3<T, TResult>(this IEnumerable<T> e, Action<T, Action<TResult>> a)
{
foreach (var i in e)
{
(bool b, TResult o) bo = default;
a(i, o => bo = (true, o));
if (bo is (true, var o))
yield return o;
}
}
static IEnumerable<TResult> SelectWhen4<T, TResult>(this IEnumerable<T> e, Func<T, Func<TResult, bool>, bool> a)
{
foreach (var i in e)
{
(bool b, TResult o) bo = default;
a(i, o => { bo = (true, o); return true; });
if (bo is (true, var o))
yield return o;
}
}
static IEnumerable<TResult> SelectNotNull<T, TResult>(this IEnumerable<T> e, Func<T, TResult?> f)
{
foreach (var i in e)
if (f(i) is { } o)
yield return o;
}
#nullable enable
record struct Bool<T>(T? t)
{
public readonly bool check = true;
public static implicit operator bool(Bool<T> bt) => true;
public static implicit operator Bool<T>(bool b) => default;
public static bool operator true(Bool<T> bt) => true;
public static bool operator false(Bool<T> bt) => false;
public static Bool<T> operator &(Bool<T> x, Bool<T> y) => y;
public static Bool<T> operator |(Bool<T> x, Bool<T> y) => y;
//public static Bool<T> operator &(bool x, Bool<T> y) => y;
}
static Bool<T> BOOL<T>(T t) => new(t);
static bool BOOL2<T>(T t) => true;
static IEnumerable<TResult> SelectWhen4<T, TResult>(this IEnumerable<T> e, Func<T, Bool<TResult>> a)
{
foreach (var i in e)
{
if (a(i) is {check: true, t: var o})
yield return o;
}
}
new[] {new{}, null, new{}}.SelectWhen4(i => i is {} ii && BOOL(i)).Display();
//var dd_ = BOOL2<int>(123 is {} ttt) && new Bool<int>(ttt);
//(ttt, dd_)
(i is > 1234 and var asd && BOOL(asd)).Display();
#nullable enable
record struct Whenable<T>(T t, bool b = true)
{
public static implicit operator Whenable<T>(bool b) => default(Whenable<T>) with { b = b };
public static bool operator true(Whenable<T> bt) => bt.b;
public static bool operator false(Whenable<T> bt) => !bt.b;
public static Whenable<T> operator &(Whenable<T> x, Whenable<T> y) => y;
}
static Whenable<T> When<T>(T t) => new(t);
new { abc = 123 } is { abc: 123 } a && When(a)
static IEnumerable<TResult> SelectWhen<T, TResult>(this IEnumerable<T> e, Func<T, Whenable<TResult>> f)
{
foreach (var i in e)
if (f(i) is {t: var o, b: true})
yield return o;
}
new[] {new{}, null, new{}}.SelectWhen(i => i is {} ii && When(ii)).Display();
https://github.com/naratteu/Naratteu.Linq/blob/main/Naratteu.Linq/SelectWhen.ipynb
https://forum.dotnetdev.kr/t/linq/13644