用于返回基于电气工程公式输入和条件条件 c# 的枚举结果的泛型类



我正在开发一个需要进行工程公式检查/验证的程序。 与单元测试非常相似,但我需要一些非常通用的东西,所以我不必创建大量的类。

我需要传递一个输入公式:示例:x = 输入电压,y = 电压参考以求分贝。 公式为 20*log10(x/y(

并验证用例应用程序的结果

例子: 如果应用程序不能超过 60 分贝且值为 72,则结果为失败。

我有很多这样的事情要做,最好有一个泛型类,将输入公式作为 Func<> 传入,然后有一个 Dictionary<[criteria],Enum.ResultType]>(或其他东西(将返回该应用程序的结果。

这是我的想法/需要的:

非工作代码,只是为了说明概念

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();
}
}

我所显示的内容显然存在很多问题(例如字典键没有唯一值(,但希望我想要完成的目标很明确,并且您可以想到一种聪明的方法来做到这一点。

这是我的建议:

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;
}
}

一个可能的解决方案。我试图添加评论以使其不言自明。

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);
}
}

谢谢大家的时间和精力。 我今天早上发现要求已经改变,包括验证消息,为什么标准失败需要在 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));
}
}

最新更新