[英]Refactor this C# code to a more elegant version
我正在嘗試將此代碼重構為更優雅的版本。 誰能幫忙。
public interface IEval<T>
{
Func<T, bool> Expression { get; }
Operator Operator { get; }
string Key { get; }
}
public static bool Validate<T>(this T o, IList<IEval<T>> conditions)
{
var returnResult = true;
var counter = 0;
foreach (var condition in conditions)
{
var tempResult = condition.Expression(o);
if (counter == 0) //don't like this
{
returnResult = tempResult;
counter++;
}
else
{
switch (condition.Operator) //don't like this
{
case Operator.And:
returnResult &= tempResult;
break;
case Operator.Or:
returnResult |= tempResult;
break;
default:
throw new NotImplementedException();
}
}
}
return returnResult;
}
謝謝!
代碼已更新:
public interface IEval<T>
{
Func<T, bool> Expression { get; }
bool Eval(bool against, T t);
}
public class AndEval<T> : IEval<T>
{
public Func<T, bool> Expression { get; private set; }
public AndEval(Func<T, bool> expression)
{
Expression = expression;
}
public bool Eval(bool against, T t)
{
return Expression.Invoke(t) & against;
}
}
public class OrEval<T> : IEval<T>
{
public Func<T, bool> Expression { get; private set; }
public OrEval(Func<T, bool> expression)
{
Expression = expression;
}
public bool Eval(bool against, T t)
{
return Expression.Invoke(t) | against;
}
}
public static class EvalExtensions
{
public static bool Validate<T>(this T t, IList<IEval<T>> conditions)
{
var accumulator = conditions.First().Expression(t);
foreach (var condition in conditions.Skip(1))
{
accumulator = condition.Eval(accumulator, t);
}
return accumulator;
}
}
試試這個(假設條件不為空)
var accumulator = conditions.First().Expression(0);
foreach (var condition in conditions.Skip(1))
{
accumulator = condition.Operation.Evaluate(
condition.Expression(0), accumulator);
}
class AddOperation : Operation
{
public override int Evaluate(int a, int b)
{
return a & b;
}
}
你明白了。 您可以通過在條件上定義一個方法來使其更加緊湊,使其可以在其自身上運行Expression()並將結果作為第一個參數傳遞給Evaluate:
condition.Evaluate(accumulator);
class Condition
{
public int Evaluate(int argument)
{
return Operation.Evaluate(Expression(0), argument);
}
}
(也是不相關的建議:永遠不要調用變量tempSomething,這是不好的業力,給人的印象是您不完全了解該特定變量對讀者的作用)
消除if / switch的一種通用模式是將邏輯放在要操作的類中的if后面。 我對您的域名了解不多,無法判斷在這里是否有效。
要應用該模式,IEval將使用其他方法進行擴展,例如
IEval<T>.PerformOperation(T tempResult)
IEval的每個具體實現都將根據其建模的特定操作來實現PerformOperation,而不是使用Enum來指示操作的類型。
(根據您的代碼不確定tempResult是否為T類型)。
然后,而不是開關,寫
returnResult = condition.PerformOperation(tempResult);
我會使用LINQ方法。 喜歡 -
public static bool Validate<T>(this T o, IList<IEval<T>> conditions)
{
return conditions
.Skip(1)
.Aggregate(
conditions.First().Expression(o),
(a, b) => b.Operator == Operators.Or ? (a || b.Expression(o)) : (a && b.Expression(o))
);
}
或者,如果您不喜歡三元運算符或需要更多可擴展且更好的方法,則可以使用Dictionary來存儲和查找與運算符關聯的函數。
public static bool Validate<T>(this T o, IList<IEval<T>> conditions)
{
return conditions
.Skip(1)
.Aggregate(
conditions.First().Expression(o),
(a, b) => operators[b.Operator](a, b.Expression(o))
);
}
public static Dictionary<Operator, Func<bool, bool, bool>> operators = new Dictionary<Operator, Func<bool, bool, bool>>()
{
{Operator.And, (a, b) => a && b},
{Operator.Or, (a, b) => a || b}
}
我唯一能想到的是:
使用if語句檢查您是否具有至少2個條件。
然后,而不是foreach,請使用帶有從第二個條件開始的計數器的常規for語句。
如果條件為零,則返回true。 取決於您的其他業務邏輯。
如果您有一個條件,則取值。
無論如何,我相信執行該操作的switch語句將是必需的...除非您更改代碼以執行某種類型的腳本,而這正是您要執行的實際操作。 我認為這更糟。
我唯一不喜歡的是您有一個名為counter的變量,該變量始終為0或1。我將其設為bool isFirst
。 如果要擺脫此開關,可以將IEval接口替換為
public interface IEval<T>{
Func<T, bool> Expression { get; }
Func<bool, bool, bool> Combinator { get; }
string Key { get; }
}
您的Combine方法將是
public Func<bool, bool, bool> Combinator {
get { return (b1, b2) => b1 | b2; }
}
要么
public Func<bool, bool, bool> Combinator {
get { return (b1, b2) => b1 & b2; }
}
取決於所需的操作。
不過,返回委托可能會過大,也許只是添加方法bool Combine(bool value1, bool value2)
以下算法表現出短路(一旦已知條件為假,它將停止評估)。 它具有相同的基本設計,但在一開始就有效地使用了隱式true && ...
使事情變得更整潔。
public static bool Validate<T>(this T o, IList<IEval<T>> conditions)
{
bool result = true;
Operator op = Operator.And;
var conditionIter = conditions.GetEnumerator();
while (result && conditionIter.MoveNext())
{
bool tempResult = conditionIter.Current.Expression(o);
switch (op)
{
case Operator.And:
result &= tempResult;
break;
case Operator.Or:
result |= tempResult;
break;
default:
throw new NotImplementedException();
}
op = condition.Operator;
}
return result;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.