我从事一个需要进行工程公式检查/验证的程序。非常类似于单元测试,但我需要一些非常通用的东西,所以我不需要做大量的类。
I需要传递一个输入公式:示例:x=输入电压,y=电压参考,以求分贝。方程为20*log10 10(x/y)
并验证用例应用程序的结果。
例句:如果应用程序不能超过60分贝,值为72,则结果失败。
我有这么多这样的工作要做,所以最好有一个泛型类,将输入公式作为Func<>传入,然后有一个Dictionary (或其他什么)来返回该应用程序的结果。
以下是我的想法/需要:
非工作代码,只是为了说明概念。
public enum CiteriaCheckResult
{
Inconclusive,
Fail,
Warning,
Pass
}
//T is the return type of the specific engineering formula
public class CriteriaCheck<T>
{
public Dictionary<?, CiteriaCheckResult> Criteria { get; set; } = new Dictionary<?, CiteriaCheckResult>();
//T1 and T2 are the inputs for a specific engineering formula
//T is the output value to test against the criteria conditions
public CiteriaCheckResult Validate<T1, T2>(Func<T1, T2, T> input)
{
//nested if's?
//switch case?
//Criteria.FirstOrDefault(k => k.Key == input result == criteria)?
return CiteriaCheckResult base on dictionary or other user configurable criteria type;
}
}想要的用法:
class Program
{
static void Main(string[] args)
{
var test1 = new CriteriaCheck<double>();
//add criteria for specific application
Criteria.Add("criteria to check against input result", CiteriaCheckResult.Inconclusive);
Criteria.Add("value is < [] && value is > []", CiteriaCheckResult.Fail);
Criteria.Add("value is <= Room.Value", CiteriaCheckResult.Pass);
Criteria.Add("if value is > -6", CiteriaCheckResult.Warning);
double x = 1.23;
double y = .7549;
//run func and return enum based on user set conditions
Console.WriteLine($"Test 1: {test1.Validate<double, double>((x,y) => 20 * Math.Log10(x/y))}");
Console.ReadKey();
}
}很明显,我所展示的东西有很多问题(比如字典键没有唯一的值),但希望我想要实现的目标是明确的,你可以想出一个聪明的方法来做到这一点。
发布于 2020-06-08 18:37:21
谢谢你们的时间和精力。今天早上我发现需求发生了变化,包括验证消息,为什么需要在GUI上显示标准失败的原因。
因此,我将创建一个实现INotifyDataErrorInfo的基类,并为每个验证类型创建一个类。会有更多的类,但是泛型类不能处理所有的新需求。
示例用法
public class EquipmentRackSizeCriteriaCheck : CriteriaCheckItemBase
{
public override void Initialize()
{
//set description
CheckProperty = "Check Equipment Enclosure Size";
//set validation rules
AddValidationRule<EquipmentRackSizeCriteriaCheck, double>(CiteriaCheckResult.Fail, "Equipment is too tall for the Enclosure", t => t.EquipmentRUHeight > t.EnclosureRUHeight);
AddValidationRule<EquipmentRackSizeCriteriaCheck, double>(CiteriaCheckResult.Warning, "Enclosure is taller than the Equipment", t => t.EquipmentRUHeight < t.EnclosureRUHeight);
AddValidationRule<EquipmentRackSizeCriteriaCheck, double>(CiteriaCheckResult.Pass, "Equipment height fits in the Enclosure", t => t.EquipmentRUHeight == t.EnclosureRUHeight);
AddValidationRule<EquipmentRackSizeCriteriaCheck, double>(CiteriaCheckResult.Fail, "Equipment is too wide for the Enclosure", t => t.EquipmentRUWidth > t.EnclosureRUWidth);
AddValidationRule<EquipmentRackSizeCriteriaCheck, double>(CiteriaCheckResult.Warning, "Enclosure is wider than the Equipment", t => t.EquipmentRUWidth < t.EnclosureRUWidth);
AddValidationRule<EquipmentRackSizeCriteriaCheck, double>(CiteriaCheckResult.Pass, "Equipment width fits in the Enclosure", t => t.EquipmentRUWidth == t.EnclosureRUWidth);
//initialize complete
base.Initialize();
}
public int EquipmentRUHeight { get; set; }
public int EquipmentRUWidth { get; set; }
public int EnclosureRUHeight { get; set; }
public int EnclosureRUWidth { get; set; }
}基类
public class CriteriaCheckItemBase : INotifyDataErrorInfo, ISupportInitializeNotification
{
private Dictionary<CiteriaCheckResultType, Dictionary<string, LambdaExpression>> _validationDictionary = new Dictionary<CiteriaCheckResultType, Dictionary<string, LambdaExpression>>();
public CriteriaCheckItemBase()
{
//intialize object
BeginInit();
}
public virtual void Initialize()
{
//set description
//CheckProperty = "";
//set validation rules
//initialize complete
EndInit();
}
public string CheckProperty { get; set; }
public CiteriaCheckResultType CheckResult { get; set; }
public string CheckMessage { get; set; }
public ObservableCollection<CriteriaCheckResult> ResultsCollection { get; set; } = new ObservableCollection<CriteriaCheckResult>();
public void AddValidationRule<T1, T2>(CiteriaCheckResultType checkResult, string message, Expression<Func<T1, bool>> rule) where T1 : CriteriaCheckItemBase
{
if (!_validationDictionary.ContainsKey(checkResult))
{
_validationDictionary.TryAdd(checkResult, new Dictionary<string, LambdaExpression>());
}
if (_validationDictionary.TryGetValue(checkResult, out Dictionary<string, LambdaExpression> rules))
{
rules.TryAdd(message ?? "No Message for this Result", rule);
}
}
#region INotifyDataErrorInfo
public bool HasErrors => (GetErrors("") is Dictionary<CiteriaCheckResultType, List<string>> c) ? c.Count > 0 : false;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName)
{
var results = _validationDictionary.OrderBy(o => (int)o.Key).ToDictionary(k => k.Key, v => v.Value.Where(c => (bool)c.Value.Compile().DynamicInvoke(this)).Select(s => s.Key).ToList());
ResultsCollection.Clear();
foreach (CiteriaCheckResultType resultType in results.Keys)
{
foreach (string msg in results[resultType])
{
ResultsCollection.Add(new CriteriaCheckResult() { CheckResult = resultType, CheckMessage = msg });
}
}
return ResultsCollection;
}
#endregion
#region ISupportInitializeNotification
public event EventHandler Initialized;
private bool _isInitialized;
public bool IsInitialized
{
get { return _isInitialized; }
private set
{
_isInitialized = value;
if (_isInitialized) { RaiseInitialized(); }
}
}
public void BeginInit()
{
if (IsInitialized) { IsInitialized = false; }
else { Initialize(); }
}
public void EndInit()
{
IsInitialized = true;
}
#endregion
protected void RaiseInitialized()
{
this.Initialized?.Invoke(this, new EventArgs());
}
public void RaisErrorChanged([CallerMemberName] string propertyName = null)
{
this.ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
}
}发布于 2020-06-06 20:31:56
以下是我的建议:
class Program
{
static void Main(string[] args)
{
var checker = new CriteriaCheck<double>
{
FailValidator = (input => input < 0)
};
var result = checker.Validate((x, y) => x * y, 1.2, 0.7);
}
}
public enum CiteriaCheckResult
{
Inconclusive,
Fail,
Warning,
Pass
}
public class CriteriaCheck<T>
{
public Func<T, bool> InconclusiveValidator { get; set; } = p => false;
public Func<T, bool> FailValidator { get; set; } = p => false;
public Func<T, bool> WarningValidator { get; set; } = p => false;
public CiteriaCheckResult Validate<T1, T2>(Func<T1, T2, T> input, T1 t1, T2 t2)
{
if (InconclusiveValidator(input(t1, t2)))
return CiteriaCheckResult.Inconclusive;
else if (FailValidator(input(t1, t2)))
return CiteriaCheckResult.Fail;
else if (WarningValidator(input(t1, t2)))
return CiteriaCheckResult.Warning;
else
return CiteriaCheckResult.Pass;
}
}发布于 2020-06-07 19:15:40
一种可能的解决办法。我试着添加一些评论,让它变得不言自明。
public enum CiteriaCheckResult
{
Inconclusive,
Fail,
Warning,
Pass
}
//T is the return type of the specific engineering formula
public class CriteriaCheck<T>
{
public Dictionary<Type, object[]> Criteria = new Dictionary<Type, object[]>();
//T1 and T2 are the inputs for a specific engineering formula
//T is the output value to test against the criteria conditions
public CiteriaCheckResult Validate<T1, T2>(Func<T1, T2, T> input, T1 x, T2 y)
{
if(Criteria.Keys.Contains(input.GetType()))
{
// Calculate/Run the Func the value from incoming parameters
T result = input(x, y);
object[] m1 = Criteria[input.GetType()];
// Calculate/Run the Func existing in the Array
T m2 = (m1[0] as Func<T1, T2, T>)(x, y);
if(result.Equals(m2))
{
// If the values match then:
return (CiteriaCheckResult)m1[1];
}
}
return CiteriaCheckResult.Inconclusive;
}
}
class Program
{
static void Main(string[] args)
{
Func<decimal, decimal, int> n1 = (x,y) => 1;
Func<int, int> n2 = (x) => 5;
Func<decimal, decimal, decimal> n3 = (x, y) => 3;
CriteriaCheck<decimal> test = new CriteriaCheck<decimal>();
object[] obj0 = { n1, CiteriaCheckResult.Fail };
test.Criteria.Add(n1.GetType(), obj0);
object[] obj1 = { n2, CiteriaCheckResult.Inconclusive };
test.Criteria.Add(n2.GetType(), obj1);
object[] obj2 = { n3, CiteriaCheckResult.Pass };
test.Criteria.Add(n3.GetType(), obj2);
var result = test.Validate(n3, 1, 2);
}
}https://stackoverflow.com/questions/62234567
复制相似问题