Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.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#_Linq_Ienumerable_Matching_Rules - Fatal编程技术网

C# 查找(并提取)复杂关联以查找规则冲突

C# 查找(并提取)复杂关联以查找规则冲突,c#,linq,ienumerable,matching,rules,C#,Linq,Ienumerable,Matching,Rules,我正在编写一些写得不是很好的代码,并且涉及一些我希望重构的相当复杂的逻辑。本主题是验证规则和报告潜在违规行为。不幸的是,这个类的设计很奇怪,所以我遇到了一些难以计数的挑战 作为一个简化的例子,我有以下几点: IEnumerable<RuleDefinition> IEnumerable<Request> 显然,当请求类型匹配并且两个请求之间的间隔(TimeIndex)太短时,就违反了该规则。现在,我想摘录: 如果存在违反规则的情况(这相当容易) 违反了哪些规则 哪些请

我正在编写一些写得不是很好的代码,并且涉及一些我希望重构的相当复杂的逻辑。本主题是验证规则和报告潜在违规行为。不幸的是,这个类的设计很奇怪,所以我遇到了一些难以计数的挑战

作为一个简化的例子,我有以下几点:

IEnumerable<RuleDefinition>
IEnumerable<Request>
显然,当请求类型匹配并且两个请求之间的间隔(TimeIndex)太短时,就违反了该规则。现在,我想摘录:

  • 如果存在违反规则的情况(这相当容易)
  • 违反了哪些规则
  • 哪些请求违反了规则
因此,在我们的情况下,我想得到如下结果:

public class Violation
{
    public RuleDefinition ViolatedRule { get; set; }
    public Request FirstRequest { get; set; }
    public Request SecondRequest { get; set; }
}
class ViolationFinder : IViolationFinder
{
    public IEnumerable<Violation> Search(IEnumerable<RuleDefinition> ruleDefinitions, IEnumerable<Request> requests)
    {
        List<Request> requestList = requests.ToList();
        return ruleDefinitions.SelectMany(rule => FindViolationsInRequests(requestList, rule));
    }

    private IEnumerable<Violation> FindViolationsInRequests(IEnumerable<Request> allRequest, RuleDefinition rule)
    {
        return FindMatchingRequests(allRequest, rule)
                .Select(firstRequest => FindSingleViolation(allRequest, firstRequest, rule))
                .Where(violation => violation != null);
    }

    private Violation FindSingleViolation(IEnumerable<Request> allRequest, Request request, RuleDefinition rule)
    {
        Request collidingRequest = FindCollidingRequest(allRequest, request, rule.MinimumDistanceBetweenRequests);

        if (collidingRequest != null)
        {
            return new Violation
            {
                ViolatedRule = rule,
                FirstRequest = request,
                SecondRequest = collidingRequest
            };
        }

        return null;
    }

    private IEnumerable<Request> FindMatchingRequests(IEnumerable<Request> requests, RuleDefinition rule)
    {
        return requests.Where(r => r.TypeOfThisRequest == rule.ConcerningRequestType);
    }

    private Request FindCollidingRequest(IEnumerable<Request> requests, Request firstRequest, int minimumDistanceBetweenRequests)
    {
        return requests.FirstOrDefault(secondRequest => IsCollidingRequest(firstRequest, secondRequest, minimumDistanceBetweenRequests));
    }

    private bool IsCollidingRequest(Request firstRequest, Request secondRequest, int minimumDistanceBetweenRequests)
    {
        return secondRequest.TimeIndex > firstRequest.TimeIndex &&
               Math.Abs(secondRequest.TimeIndex - firstRequest.TimeIndex) < minimumDistanceBetweenRequests;
    }
}
我认为这是一个相当简单的问题,但我没能找到一个可读性和可维护性都很好的解决方案。我试过各种各样的东西。。结果总是乱七八糟的(我刚刚尝试实现这个示例,结果很糟糕)

在这种情况下有什么想法和模式可以使用吗? (Resharper经常正确地建议。选择Many,但这会使内容更不可读)

编辑:这是我漫长而丑陋的实现

var ruleDefinitions=新列表
{ 
新规则定义{
ConcerningRequestType=RequestType.Exclusive,
请求之间的最小距离=2}
};
var请求=新列表()
{
新请求{TimeIndex=1,TypeOfThisRequest=RequestType.Normal},
新请求{TimeIndex=1,TypeOfThisRequest=RequestType.Normal},
新请求{TimeIndex=2,TypeOfThisRequest=RequestType.Normal},
新请求{TimeIndex=3,TypeOfThisRequest=RequestType.Exclusive},
新请求{TimeIndex=4,TypeOfThisRequest=RequestType.Exclusive},
};
var违规=新列表();
foreach(规则定义中的var规则)
{
var requestsMatchingType=requests.Where(r=>r.TypeOfThisRequest==rule.ConcerningRequestType);
foreach(requestsMatchingType中的var firstRequest)
{
var collidingRequest=requests.FirstOrDefault(secondRequest=>
secondRequest.TimeIndex>firstRequest.TimeIndex&&
Math.Abs(secondRequest.TimeIndex-firstRequest.TimeIndex)
这不是一项简单的任务,因此我要做的第一件事是定义一个接口,以查看我在这里需要什么:

interface IViolationFinder
{
    IEnumerable<Violation> Search(
        IEnumerable<RuleDefinition> ruleDefinitions, 
        IEnumerable<Request> requests);
}
接口IViolationFinder
{
IEnumerable搜索(
IEnumerable规则定义,
i无数请求);
}
现在我们清楚地看到我们需要实施什么。因为你的搜索逻辑非常复杂,我认为你不应该用一个linq来表达它。你可以,但你不应该。嵌入linq的两个嵌套foreach循环非常糟糕,我认为使用linq本身不会更干净

您需要的是在实现中创建更多的方法。这将增加可读性。因此,天真的实现是这样的(这是你的):

类ViolationFinder:IViolationFinder
{
公共IEnumerable搜索(IEnumerable规则定义、IEnumerable请求)
{
var违规=新列表();
foreach(规则定义中的var规则)
{
var requestsMatchingType=requests.Where(r=>r.TypeOfThisRequest==rule.ConcerningRequestType);
foreach(requestsMatchingType中的var firstRequest)
{
var collidingRequest=requests.FirstOrDefault(secondRequest=>
secondRequest.TimeIndex>firstRequest.TimeIndex&&
Math.Abs(secondRequest.TimeIndex-firstRequest.TimeIndex)
你可以开始重构这个。与其用一种方法思考,不如让我们提取最明显的部分:

class ViolationFinder : IViolationFinder
{
    public IEnumerable<Violation> Search(IEnumerable<RuleDefinition> ruleDefinitions, IEnumerable<Request> requests)
    {
        var violations = new List<Violation>();
        foreach (RuleDefinition rule in ruleDefinitions)
        {
            IEnumerable<Request> requestsMatchingType = requests.Where(r => r.TypeOfThisRequest == rule.ConcerningRequestType);
            violations.AddRange(
                FindViolationsInRequests(requestsMatchingType, requests, rule));
        }

        return violations;
    }

    private IEnumerable<Violation> FindViolationsInRequests(
        IEnumerable<Request> matchingRequests,
        IEnumerable<Request> allRequest,
        RuleDefinition rule)
    {
        foreach (Request firstRequest in matchingRequests)
        {
            var collidingRequest = allRequest.FirstOrDefault(secondRequest =>
                secondRequest.TimeIndex > firstRequest.TimeIndex &&
                Math.Abs(secondRequest.TimeIndex - firstRequest.TimeIndex) < rule.MinimumDistanceBetweenRequests);

            if (collidingRequest != null)
            {
                yield return new Violation
                {
                    ViolatedRule = rule,
                    FirstRequest = firstRequest,
                    SecondRequest = collidingRequest
                };
            }
        }
    }
}
类ViolationFinder:IViolationFinder
{
公共IEnumerable搜索(IEnumerable规则定义、IEnumerable请求)
{
var违规=新列表();
foreach(规则定义中的规则定义规则)
{
IEnumerable requestsMatchingType=requests.Where(r=>r.TypeOfThisRequest==rule.ConcerningRequestType);
AddRange.AddRange(
FindViolationsRequests(requestsMatchingType、requests、rule));
}
返回违规行为;
}
私有IEnumerable FindViolationsInRequests(
IEnumerable匹配请求,
IEnumerable allRequest,
规则(定义规则)
{
foreach(matchingRequests中的Request firstRequest)
{
var collingrequest=allRequest.FirstOrDefault(secondRequest=>
secondRequest.TimeIndex>firstRequest.TimeIndex&&
Math.Abs(secondRequest.TimeIndex-firstRequest.TimeIndex)
搜索几乎是清白的,但我们是清白的
class ViolationFinder : IViolationFinder
{
    public IEnumerable<Violation> Search(IEnumerable<RuleDefinition> ruleDefinitions, IEnumerable<Request> requests)
    {
        var violations = new List<Violation>();
        foreach (var rule in ruleDefinitions)
        {
            var requestsMatchingType = requests.Where(r => r.TypeOfThisRequest == rule.ConcerningRequestType);
            foreach (var firstRequest in requestsMatchingType)
            {
                var collidingRequest = requests.FirstOrDefault(secondRequest =>
                    secondRequest.TimeIndex > firstRequest.TimeIndex &&
                    Math.Abs(secondRequest.TimeIndex - firstRequest.TimeIndex) < rule.MinimumDistanceBetweenRequests);

                if (collidingRequest != null)
                {
                    violations.Add(new Violation
                    {
                        ViolatedRule = rule,
                        FirstRequest = firstRequest,
                        SecondRequest = collidingRequest
                    });
                }
            }
        }

        return violations;
    }
}
class ViolationFinder : IViolationFinder
{
    public IEnumerable<Violation> Search(IEnumerable<RuleDefinition> ruleDefinitions, IEnumerable<Request> requests)
    {
        var violations = new List<Violation>();
        foreach (RuleDefinition rule in ruleDefinitions)
        {
            IEnumerable<Request> requestsMatchingType = requests.Where(r => r.TypeOfThisRequest == rule.ConcerningRequestType);
            violations.AddRange(
                FindViolationsInRequests(requestsMatchingType, requests, rule));
        }

        return violations;
    }

    private IEnumerable<Violation> FindViolationsInRequests(
        IEnumerable<Request> matchingRequests,
        IEnumerable<Request> allRequest,
        RuleDefinition rule)
    {
        foreach (Request firstRequest in matchingRequests)
        {
            var collidingRequest = allRequest.FirstOrDefault(secondRequest =>
                secondRequest.TimeIndex > firstRequest.TimeIndex &&
                Math.Abs(secondRequest.TimeIndex - firstRequest.TimeIndex) < rule.MinimumDistanceBetweenRequests);

            if (collidingRequest != null)
            {
                yield return new Violation
                {
                    ViolatedRule = rule,
                    FirstRequest = firstRequest,
                    SecondRequest = collidingRequest
                };
            }
        }
    }
}
class ViolationFinder : IViolationFinder
{
    public IEnumerable<Violation> Search(IEnumerable<RuleDefinition> ruleDefinitions, IEnumerable<Request> requests)
    {
        var violations = new List<Violation>();
        foreach (RuleDefinition rule in ruleDefinitions)
        {
            violations.AddRange(FindViolationsInRequests(requests, rule));
        }

        return violations;
    }

    private IEnumerable<Violation> FindViolationsInRequests(
        IEnumerable<Request> allRequest,
        RuleDefinition rule)
    {
        foreach (Request firstRequest in FindMatchingRequests(allRequest, rule))
        {
            var collidingRequest = allRequest.FirstOrDefault(secondRequest =>
                secondRequest.TimeIndex > firstRequest.TimeIndex &&
                Math.Abs(secondRequest.TimeIndex - firstRequest.TimeIndex) < rule.MinimumDistanceBetweenRequests);

            if (collidingRequest != null)
            {
                yield return new Violation
                {
                    ViolatedRule = rule,
                    FirstRequest = firstRequest,
                    SecondRequest = collidingRequest
                };
            }
        }
    }

    private IEnumerable<Request> FindMatchingRequests(IEnumerable<Request> requests, RuleDefinition rule)
    {
        return requests.Where(r => r.TypeOfThisRequest == rule.ConcerningRequestType);
    }
}
    var collidingRequest = allRequest.FirstOrDefault(secondRequest =>
        secondRequest.TimeIndex > firstRequest.TimeIndex &&
        Math.Abs(secondRequest.TimeIndex - firstRequest.TimeIndex) < rule.MinimumDistanceBetweenRequests);
class ViolationFinder : IViolationFinder
{
    public IEnumerable<Violation> Search(IEnumerable<RuleDefinition> ruleDefinitions, IEnumerable<Request> requests)
    {
        var violations = new List<Violation>();

        foreach (RuleDefinition rule in ruleDefinitions)
        {
            violations.AddRange(FindViolationsInRequests(requests, rule));
        }

        return violations;
    }

    private IEnumerable<Violation> FindViolationsInRequests(
        IEnumerable<Request> allRequest,
        RuleDefinition rule)
    {
        foreach (Request firstRequest in FindMatchingRequests(allRequest, rule))
        {

            Request collidingRequest = FindCollidingRequest(allRequest, firstRequest, rule.MinimumDistanceBetweenRequests);

            if (collidingRequest != null)
            {
                yield return new Violation
                {
                    ViolatedRule = rule,
                    FirstRequest = firstRequest,
                    SecondRequest = collidingRequest
                };
            }
        }
    }

    private IEnumerable<Request> FindMatchingRequests(IEnumerable<Request> requests, RuleDefinition rule)
    {
        return requests.Where(r => r.TypeOfThisRequest == rule.ConcerningRequestType);
    }

    private Request FindCollidingRequest(IEnumerable<Request> requests, Request firstRequest, int minimumDistanceBetweenRequests)
    {
        return requests.FirstOrDefault(secondRequest => IsCollidingRequest(firstRequest, secondRequest, minimumDistanceBetweenRequests));
    }

    private bool IsCollidingRequest(Request firstRequest, Request secondRequest, int minimumDistanceBetweenRequests)
    {
        return secondRequest.TimeIndex > firstRequest.TimeIndex &&
               Math.Abs(secondRequest.TimeIndex - firstRequest.TimeIndex) < minimumDistanceBetweenRequests;
    }
}
class ViolationFinder : IViolationFinder
{
    public IEnumerable<Violation> Search(IEnumerable<RuleDefinition> ruleDefinitions, IEnumerable<Request> requests)
    {
        List<Request> requestList = requests.ToList();
        return ruleDefinitions.SelectMany(rule => FindViolationsInRequests(requestList, rule));
    }

    private IEnumerable<Violation> FindViolationsInRequests(IEnumerable<Request> allRequest, RuleDefinition rule)
    {
        return FindMatchingRequests(allRequest, rule)
                .Select(firstRequest => FindSingleViolation(allRequest, firstRequest, rule))
                .Where(violation => violation != null);
    }

    private Violation FindSingleViolation(IEnumerable<Request> allRequest, Request request, RuleDefinition rule)
    {
        Request collidingRequest = FindCollidingRequest(allRequest, request, rule.MinimumDistanceBetweenRequests);

        if (collidingRequest != null)
        {
            return new Violation
            {
                ViolatedRule = rule,
                FirstRequest = request,
                SecondRequest = collidingRequest
            };
        }

        return null;
    }

    private IEnumerable<Request> FindMatchingRequests(IEnumerable<Request> requests, RuleDefinition rule)
    {
        return requests.Where(r => r.TypeOfThisRequest == rule.ConcerningRequestType);
    }

    private Request FindCollidingRequest(IEnumerable<Request> requests, Request firstRequest, int minimumDistanceBetweenRequests)
    {
        return requests.FirstOrDefault(secondRequest => IsCollidingRequest(firstRequest, secondRequest, minimumDistanceBetweenRequests));
    }

    private bool IsCollidingRequest(Request firstRequest, Request secondRequest, int minimumDistanceBetweenRequests)
    {
        return secondRequest.TimeIndex > firstRequest.TimeIndex &&
               Math.Abs(secondRequest.TimeIndex - firstRequest.TimeIndex) < minimumDistanceBetweenRequests;
    }
}
public IEnumerable<Violation> Search(IEnumerable<RuleDefinition> ruleDefinitions, IEnumerable<Request> requests)
{
    List<Request> requestList = requests.ToList();
    return ruleDefinitions.SelectMany(rule => FindViolationsInRequests(requestList, rule));
}
var violations = from rule in ruleDefinitions
                 join r1 in requests on rule.ConcerningRequestType equals r1.TypeOfThisRequest
                 join r2 in requests on rule.ConcerningRequestType equals r2.TypeOfThisRequest
                 where r1 != r2 &&
                       r2.TimeIndex > r1.TimeIndex &&
                       Math.Abs(r2.TimeIndex - r1.TimeIndex) < rule.MinimumDistanceBetweenRequests
                 select new Violation() { FirstRequest = r1, SecondRequest = r2, ViolatedRule = rule };