Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/EmptyTag/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 设计需求满足结构_C# - Fatal编程技术网

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