如果工作请求当前应用了一个或多个状态,那么bitmasks是否是建模的好方法,哪些更好?

时间:2017-08-25 19:24:49

标签: c# sql-server bitmask

摘要

需要能够判断工作请求当前是否具有一个或多个状态,并且能够在不影响其他状态的情况下删除状态。目前,工作请求一次只能有一个状态,而用于确定最重要的工作的代码是什么?地位不断增长。

SQL服务器后端,C#与EF(主要)进行数据访问

背景

我正在处理一个我们有工作请求的应用程序,其中状态会随着人们执行特定活动而更改,直到请求完成为止。请求可以有近30种状态,并且在许多情况下我们需要知道是否已将一个或多个状态应用于工作请求(以确定接下来会发生什么)。

目前,请求具有反映最新状态的单一状态,当我们更改状态时,它必须通过查看其他相关数据的代码来确定最重要的“最重要”状态。状态是并将请求更改为该请求。

这个业务问题似乎非常适合使用按位计算,但我不想采用过时的做法。另一种可能性是只拥有一组状态并从列表中添加/删除。

由于

2 个答案:

答案 0 :(得分:2)

  

X不要对开放集(例如操作系统)使用枚举   版本,朋友的姓名等。)。

[Microsoft Framework Design Guidelines]

您的用例听起来像一个随着时间的推移而添加的开放式设置。因此,基于此,我说enum不适合这个用例。

  

X AVOID 创建标记枚举,其中某些值组合无效。

另外,它听起来并不像你的枚举中的所有值都可以合并并且仍然有效。

最后,Steven Clarke在Microsoft Framework Design Guidelines的已发布副本中发表了关于您提议使用枚举的复杂性的评论:

  

我确信经验不足的开发人员能够理解   标志上的按位运算。但真正的问题在于它们是否存在   我希望不得不这样做。我运行的大多数API   通过实验室不要求他们执行此类操作,所以我   感觉他们会有与我们相同的经历   在最近的一项研究中观察到 - 它不是它们的东西   过去这样他们甚至可能都没想过。哪里可以得到   更糟糕的是,我认为,如果不太先进的开发人员不了解他们   正在使用一组可以相互组合的标志,   他们可能只是查看可用的列表并认为这就是全部   他们可以访问的功能。正如我们在其他研究中所见,如果是   API使它看起来像一个特定的场景或要求   现在不可能,他们可能会改变   要求并做似乎可能的事情,而不是做   有动力花时间调查他们需要做什么来实现   最初的目标。

以下是关于枚举的一些想法,如果你走这条路:

  

DO 使用复数名词或名词短语以及带有单数名词或名词短语的简单枚举来命名标记枚举。

     

DO 对标志枚举值使用2的幂,因此可以使用按位OR运算自由组合它们。

答案 1 :(得分:0)

我认为使用已标记的枚举对您的状态不一定有任何错误。为了澄清,我认为你正在谈论两件事。已为请求执行的操作集,然后是您希望与用户通信的某种派生值,这是最重要的值。认为这可以通过执行标记的枚举,然后从您的状态枚举派生的属性(您可能已经这样做)来处理。我还建议记录每个状态何时应用于单独实体中的请求。

就执行您的状态而言,您可以尝试的一件事是将您的流程表示为每个步骤的有向图。然后,该数据结构可用于确定是否满足所有条件以进入流程中的下一步。

In [88]: c
Out[88]: 
                       Address    Name
CustomerID                            
10            Address for Mike    Mike
11          Address for Marcia  Marcia

In [89]: c.index
Out[89]: Int64Index([10, 11], dtype='int64', name='CustomerID')

In [90]: orders
Out[90]: 
   CustomerID   OrderDate
0          10  2014-12-01
1          11  2014-12-01
2          10  2014-12-01

In [91]: orders.index
Out[91]: RangeIndex(start=0, stop=3, step=1)

In [92]: c.merge(orders)
---------------------------
MergeError: No common columns to perform merge on

记录状态更改的可能类

[Flags]
public enum Status
{
    Unknown = 0,
    Completed = 1,
    Blocked = 2,
    Phase1 = 4,
    Phase2 = 8,
    Phase3 = 16,
    Closed = 32
}

public class Request
{        
    public string Name { get; set; }
    public string StatusText { get { return GetStatusText(); } }
    public Status Status { get; set; }

    public Request()
    {
        this.Status = Status.Unknown;
    }

    private string GetStatusText()
    {
        string statusText = "Created";

        if (AnyStatus(Status.Closed | Status.Completed))
        {
            statusText = IsStatus(Status.Closed) ? "Closed" : "Completed";
        }
        else
        {
            if (IsStatus(Status.Blocked))
            {
                statusText = "Blocked";
            }
            else
            {
                if(IsStatus(Status.Phase3)) {
                    statusText = "Phase 3";
                }
                else if(IsStatus(Status.Phase2)) {
                    statusText = "Phase 2";
                }
                else if (IsStatus(Status.Phase1))
                {
                    statusText = "Phase 1";
                }
            }
        }

        return statusText;
    }

    private bool IsStatus(Status checkStatus)
    {
        return ((this.Status & checkStatus) == checkStatus);
    }

    private bool AnyStatus(Status checkStatus)
    {
        return ((this.Status & checkStatus) > 0);
    }
}