我正在創建一個Validator<T>
類。我試圖爲我的驗證器實現Linq SelectMany
擴展方法,以便能夠使用Linq查詢組合表達式並驗證最終結果,即使基礎值發生更改。如何撰寫Linq表達式?即Func <Exp <Func<X, Y>>,Exp <Func<Y, Z>>,Exp <Func<X, Z> >>
以下測試代碼演示了我的意圖。
var a = 2;
var b = 3;
var va = Validator.Create(() => a, n => n >= 0 && n < 5);
var vb = Validator.Create(() => b, n => n >= 0 && n < 5);
var vc = from ia in va
from ib in vb
select ia + ib;
Debug.Assert(vc.Value == a + b); //2 + 3
Debug.Assert(vc.Value == 5);
Debug.Assert(vc.IsValid == true);
a = 7;
Debug.Assert(vc.Value == a + b); //7 + 3
Debug.Assert(vc.Value == 10);
Debug.Assert(va.IsValid == false);
Debug.Assert(vb.IsValid == true);
Debug.Assert(vc.IsValid == false);
我見過以下問題How do I compose existing Linq Expressions這說明我如何使用And
表達式一起撰寫兩封Func<T, bool>
的,但我需要能夠以更,好了,功能性的方式共同組成的功能。
我有,例如,以下兩個表達式:
public Expression<Func<T>> ValueExpression { get; private set; }
public Expression<Func<T, bool>> ValidationExpression { get; private set; }
我想創建一個新的表達方式是這樣的:
public Expression<Func<bool>> IsValidExpression
{
get
{
// TODO: Compose expressions rather than compile & invoke.
}
}
更簡潔地說我想實現這些功能:
// Specific case
Func<Expression<Func<T>>, Expression<Func<T, bool>>, Expression<Func<bool>>>
// General case
Func<Expression<Func<X, Y>>, Expression<Func<Y, Z>>, Expression<Func<X, Z>>>
一般情況下的功能可以修改爲接受不同數量的通用理論根據需要組成任何功能。
我已經搜索堆棧溢出(當然)和網絡,但沒有一個例子解決了這個問題。
我的Validator<T>
類的代碼如下。
public class Validator<T>
{
public Validator(Expression<Func<T>> valueFunc,
Expression<Func<T, bool>> validationFunc)
{
this.ValueExpression = valueFunc;
this.ValidationExpression = validationFunc;
}
public Expression<Func<T>> ValueExpression { get; private set; }
public Expression<Func<T, bool>> ValidationExpression { get; private set; }
public T Value { get { return this.ValueExpression.Compile().Invoke(); } }
public bool IsValid { get { return this.IsValidExpression.Compile().Invoke(); } }
public Expression<Func<bool>> IsValidExpression
{
get
{
// TODO: Compose expressions.
}
}
}
我SelectMany
擴展包含的難吃.Compile().Invoke()
負荷,我想擺脫的。
public static Validator<U> SelectMany<T, U>(this Validator<T> @this, Expression<Func<T, Validator<U>>> k)
{
Expression<Func<T>> fvtv = @this.ValueExpression;
Expression<Func<Validator<U>>> fvu =() => k.Compile().Invoke(fvtv.Compile().Invoke());
Expression<Func<U>> fvuv = fvu.Compile().Invoke().ValueExpression;
Expression<Func<U, bool>> fvtiv = u => @this.ValidationExpression.Compile().Invoke(fvtv.Compile().Invoke());
return fvuv.ToValidator(fvtiv);
}
public static Validator<V> SelectMany<T, U, V>(this Validator<T> @this, Expression<Func<T, Validator<U>>> k, Expression<Func<T, U, V>> s)
{
Expression<Func<Validator<U>>> fvu =() => @this.SelectMany(k);
Expression<Func<T>> fvtv = @this.ValueExpression;
Expression<Func<U>> fvuv = fvu.Compile().Invoke().ValueExpression;
Expression<Func<T, bool>> fvtiv = @this.ValidationExpression;
Expression<Func<U, bool>> fvuiv = u => fvu.Compile().Invoke().ValidationExpression.Compile().Invoke(u);
Expression<Func<V>> fvv =() => s.Compile().Invoke(fvtv.Compile().Invoke(), fvuv.Compile().Invoke());
Expression<Func<V, bool>> fvviv = v => fvtiv.Compile().Invoke(fvtv.Compile().Invoke()) && fvuiv.Compile().Invoke(fvuv.Compile().Invoke());
return fvv.ToValidator(fvviv);
}
在此先感謝!
真的很難看到你的意思是「以更多功能的方式」。你需要做什麼,你不能通過刪除所有Expression <> .Compile()和.Invoke()來做到這一點? – pdr 2010-02-25 01:04:10
我很好奇你爲什麼要驗證*表達式來產生值*,而不是簡單地驗證*實際值*。你能詳細說明這一點嗎? – Aaronaught 2010-02-25 01:16:48
下面是一個例子 - 我試圖編寫函數,如f(x)= x + 1&g(x)= sqrt(x),然後h(x)= f(g(x))。現在,如果我對g有一個約束,使得x> = 0(-ve數等的sqrt),那麼我希望該約束傳播給函數h。當我的基礎值x變化時,我希望能夠問函數h是否應該考慮其結果仍然有效。 (這是一個有點人爲的例子,但它應該有助於澄清。)乾杯。 – Enigmativity 2010-02-25 09:21:41