C# 设计需求满足结构
我试图在程序中实现一个“需求”类型的系统。在我看来,这似乎很简单,但事实证明,将其抽象到足够有用比预期的要困难得多 这就是我要做的C# 设计需求满足结构,c#,C#,我试图在程序中实现一个“需求”类型的系统。在我看来,这似乎很简单,但事实证明,将其抽象到足够有用比预期的要困难得多 这就是我要做的 enum Condition { Not, Exists, Exceeds } abstract class Requirement { // base class Condition Condition { get; set; } } class ScoreRequirement : Requirement { // a specific 's
enum Condition {
Not, Exists, Exceeds
}
abstract class Requirement {
// base class
Condition Condition { get; set; }
}
class ScoreRequirement : Requirement {
// a specific 'score' is required
}
class TraitRequirement : Requirement {
// a specific 'trait' is required
}
class SatisfyingObject {
// this is the class that has to satisfy the requirements
IDictionary<Trait, int> Traits { get; set; }
}
所以这个概念看起来很简单。你会召唤一个物体
var satisfying = // get the satisfying object;
if( satisfying.Satisfies( obj.Requirements ) )
return true;
我遇到的问题实际上是如何编码满足
方法-具体来说,我不确定如何将其与条件
参数关联起来。我希望人们能够设置一些相当通用的“需求”,但这背后的逻辑对我来说非常混乱。因为在设计时还不知道这些需求,所以我不能真正地硬编码它们中的任何一个
有什么建议吗?我建议确定指定需求所需的最小范围,然后从这个范围开始,看看设计有多复杂。如果您发现即使是最小范围也会导致很多复杂性,或者您甚至无法理解最小范围是什么,那么您可能需要研究一种更灵活的方法,比如托管一种脚本语言来表达您的约束。有很多可用的库可以支持这一点,它们的支持/维护成本将低于您自己创建和改进的库,以提供设置约束的“简单”方法
如果可以的话,请保持简单,但如果确实需要复杂化,试着找到已经建立和测试的基础,以便减轻复杂性的负担。
< P>如果这不是一个学习项目,我将强烈推荐您使用已经为这个构建的东西:public interface IRuleDefinition
{
String PropertyName { get; }
String Message { get; }
}
public class ValidationRule<T>: IRuleDefinition
{
public String PropertyName { get; private set; }
public String Message { get; private set; }
private Func<T, Boolean> _isValidDelegate;
public ValidationRule(Func<T, Boolean> isValidDelegate, String propertyName, String message)
{
PropertyName = propertyName;
Message = message;
_isValidDelegate = isValidDelegate;
}
public Boolean IsValid(T objToValidate)
{
return _isValidDelegate(objToValidate);
}
}
public class Validator<T>
{
private List<ValidationRule<T>> _validationRules = new List<ValidationRule<T>>();
public void AddRule(Func<T, Boolean> isValidDelegate, String propertyName = null, String message = null)
{
_validationRules.Add(new ValidationRule<T>(isValidDelegate, propertyName, message));
}
public Boolean IsValid(T objToValidate)
{
return _validationRules.Any(vr => vr.IsValid(objToValidate));
}
public IEnumerable<IRuleDefinition> GetViolations(T objToValidate)
{
return _validationRules
.Where(vr => !vr.IsValid(objToValidate))
.Cast<IRuleDefinition>();
}
}
公共接口IRuleDefinition
{
字符串PropertyName{get;}
字符串消息{get;}
}
公共类验证规则:IRuleDefinition
{
公共字符串PropertyName{get;private set;}
公共字符串消息{get;private set;}
私人保险公司;
公共验证规则(Func-isvalidelegate、字符串属性名称、字符串消息)
{
PropertyName=PropertyName;
消息=消息;
_IsValidLegate=IsValidLegate;
}
公共布尔值IsValid(T objToValidate)
{
返回_isvalidedelegate(objToValidate);
}
}
公共类验证器
{
私有列表_validationRules=新列表();
public void AddRule(Func-isvalidelegate,String-propertyName=null,String-message=null)
{
_添加(新的ValidationRule(isValidElegate、propertyName、message));
}
公共布尔值IsValid(T objToValidate)
{
返回_validationRules.Any(vr=>vr.IsValid(objToValidate));
}
公共IEnumerable GetViolations(T objToValidate)
{
返回验证规则
.Where(vr=>!vr.IsValid(objToValidate))
.Cast();
}
}
您可以在如下代码中使用它:
var myObj = new MyObject{ Name = "Josh", Age = 29 };
var myObjValidator = new Validator<MyObject>();
myObjValidator.AddRule(
obj => !String.IsNullOrWhitespace(obj.Name),
"Name", "Name is required!");
myObjValidator.AddRule(
obj => obj.Age < 99,
"Age", "Age must be less than 99");
myObjValidator.AddRule(
obj => obj.Name == "Logan" && obj.Age < 29,
message: "RUN!!!");
if(!myObjValidator.IsValid(myObj))
{
foreach(var violation in myObjValidator.GetViolations(myObj))
Console.WriteLine("Property: {0}, Message: {1}",
violation.PropertyName, violation.Message);
}
var myObj=newmyobject{Name=“Josh”,Age=29};
var myObjValidator=新验证器();
myObjValidator.AddRule(
obj=>!String.IsNullOrWhitespace(obj.Name),
“名称”,“名称是必需的!”);
myObjValidator.AddRule(
obj=>obj.年龄<99岁,
“年龄”,“年龄必须小于99岁”);
myObjValidator.AddRule(
obj=>obj.Name==“Logan”&&obj.Age<29,
信息:“快跑!!!”;
如果(!myObjValidator.IsValid(myObj))
{
foreach(myObjValidator.GetViolations(myObj)中的var冲突)
WriteLine(“属性:{0},消息:{1}”,
violation.PropertyName、violation.Message);
}
现在,这些都来自内存,所以可能有一些可能是编码/编译器错误,但希望您能了解总体情况
同样,如果这不是一个学习项目,我已经四处寻找了这些东西,但没有发现任何东西。你知道有什么特别的地方可能是一个好的开始吗?这里有一个选项可以让你在应用程序中嵌入/执行C#脚本:Hrnm。。。不过,托管脚本语言不会让我序列化要保存在数据库中的约束,我必须这样做。这些约束将在脚本语言中表示为一个函数,它只是一个字符串,因此很容易保存到数据库中。这绝对不是一个简单的解决方案,除非你真的需要灵活性,否则我不会推荐它。谢谢!我将看一看你的例子,并试图理解它。我不能使用给定示例的原因是,规则必须存储在数据库中,因此它们必须是可序列化的,并且在运行时也不知道。它们是由最终用户添加到系统中的。@Ciel,那么您可能应该查看EntLib验证块,因为您可以将验证规则存储在代码以外的区域中。它有一种方法可以通过现成的配置文件来实现这一点,但也可以通过一些工作扩展到使用数据库。任何比这更先进的,您需要考虑使用一个成熟的业务规则引擎。其中大多数都有一个相当陡峭的学习曲线,而且,您的代码只需一次修改即可编译。使用名为的
AddRule
无法立即使用。“来自内存”的代码非常好!
var myObj = new MyObject{ Name = "Josh", Age = 29 };
var myObjValidator = new Validator<MyObject>();
myObjValidator.AddRule(
obj => !String.IsNullOrWhitespace(obj.Name),
"Name", "Name is required!");
myObjValidator.AddRule(
obj => obj.Age < 99,
"Age", "Age must be less than 99");
myObjValidator.AddRule(
obj => obj.Name == "Logan" && obj.Age < 29,
message: "RUN!!!");
if(!myObjValidator.IsValid(myObj))
{
foreach(var violation in myObjValidator.GetViolations(myObj))
Console.WriteLine("Property: {0}, Message: {1}",
violation.PropertyName, violation.Message);
}