与对象键的字典

时间:2015-01-28 10:06:00

标签: c# .net dictionary

我正在努力使用特定字典来改变对象的状态。

我的想法是我有类Process,每次用户提交要处理的东西时都会创建。进程有ID,其他一些信息和CurrentState。可能的CurrentStates在StateEnum类中定义,包含" Pending,Processing,Completed,Error"等状态。等等 之后,有一些任务/命令,用户可以执行 - 每个任务都被定义为一个类,并包含进程ID和Execute方法,它们改变了对象的状态。这些任务继承自ITask接口。

事情是,我需要某种状态机,这将验证是否可以从状态" Pending"陈述"处理"使用任务" ResumeTask"例如。对于此验证,我使用字典创建了类State,并且每次创建Process时都会创建其对象。

问题是,字典无法正常工作。让我展示代码(我创建简单的控制台应用程序只是为了演示问题),并提供一些注释并解释发生了什么:

ITask界面

public interface ITask
{

    int IntParam1 { get; set; }

    void Execute(Process proc);

}

ResumeTask类(我还有PauseTask和其他任务)

class ResumeTask : ITask
{

    int intParam1;
    public int IntParam1
    {
        get { return intParam1; }
        set { intParam1 = value; }
    }


    public void Execute(Process proc)
    {
        ResumeTask resume = new ResumeTask();
        proc.ChangeState(resume);

        //code below not working - is there a way how to make this 
        //work instead of creating new empty class above?
        //proc.ChangeState(this);
    }

    public override int GetHashCode()
    {
        return 17 + 31 * intParam1.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        ResumeTask other = obj as ResumeTask;
        return other != null && this.intParam1 == other.intParam1;
    }


}

流程类

public class Process
{

    State stat;


    private int processID;
    public int ProcessID
    {
        get { return processID; }
        private set { processID = value; }
    }

    private StateEnum state;
    public StateEnum State
    {
        get { return state; }
        set { state = value; }
    }

    public readonly int userID;
    public int UserID
    {
        get { return userID; }
    }

    public Process(int processID, int userID)
    {
        this.processID = processID;
        this.userID = userID;
        stat = new State();
        this.state = stat.CurrentState;
    }

    public void ChangeState(ITask task)
    {

        this.state = stat.MoveNext(task);

    }

}

州级

class State
{

    private class StateTransition
    {
        public StateEnum State;
        public ITask Task;

        public StateTransition(StateEnum state, ITask task)
        {
            State = state;
            Task = task;
        }

        public override int GetHashCode()
        {
            return 17 + 31 * State.GetHashCode() + 31 * Task.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            StateTransition other = obj as StateTransition;
            return other != null && this.State == other.State && this.Task == other.Task;
        }
    }


    public StateEnum CurrentState;

    Dictionary<StateTransition, StateEnum> transitions;

    ITask pause = new PauseTask();
    ITask resume = new ResumeTask();

    ITask resumenew = new ResumeTask();


    public State()
    {

        CurrentState = StateEnum.Pending;
        transitions = new Dictionary<StateTransition, StateEnum>
        {
            { new StateTransition(StateEnum.Processing, pause), StateEnum.Pending },
            { new StateTransition(StateEnum.Pending, resume), StateEnum.Processing }
        };
    }


    public StateEnum MoveNext(ITask task)
    {
        StateTransition transition = new StateTransition(CurrentState, task);
        StateEnum nextState;
        if (!transitions.TryGetValue(transition, out nextState))
        {
            return StateEnum.Error;
        }
        else
        {
            return nextState;
        }
    }

}

StateEnum枚举

public enum StateEnum
{

    Pending,
    Processing,
    Error,
    Processed,
    Downloaded

}

计划类

class Program
{
    static void Main(string[] args)
    {

        Process proc = new Process(1, 20);

        ResumeTask resumetask = new ResumeTask();
        resumetask.IntParam1 = 1;
        resumetask.Execute(proc);

        Console.WriteLine(Convert.ToString(proc.ProcessState));
        Console.ReadLine();


    }
}

让我们快速浏览一些重点:

  1. 在所有任务中,我都覆盖了Equals和GetHashCode方法,因为我已经知道必须像它一样完成,如果我想在字典中使用对象。
  2. 如果你注意到execute方法 - 问题是,当我在一个简单的例子之前测试它时,我不得不传递没有任何值的新对象,以便获得一些成功的结果 - 也许这就是因为在字典中,我有空类,但我用intParam1设置传递类并尝试比较它们?
  3. 在Process类中,我只需创建新的State对象并从中获取CurrentState。此外,方法MoveNext只是从Task
  4. 中的Execute()方法传递输入参数
  5. 在国家班,有一个最大的问题(我认为)。正如你所看到的,我不得不创建另一种类型&#34; StateTransition&#34; (这是借用StackOverflow上的状态机示例),因为在实际应用中,可以在某些状态下执行更多任务 - 并且为了在字典中具有唯一键,我必须这样做。 所以我基本上创建了类型,再次覆盖了Equald和GetHashCode,之后我创建了一个字典,其中StateTransition用作键。我不得不创建任务的空对象(暂停,恢复),以便将它们放入字典中 - 我不确定这是否是正确的方法,但它在某种程度上是有效的。 之后,我尝试找到一个键的值,该值由进程中的CurrentState和task组成,我之前在Execute()方法中传递了该值。但结果总是&#34;错误&#34;。
  6. 我尝试了几件事 - 我试图创建两个简单的词典:

    跃迁<ITask, StateEnum>;
     availableTasks <StateEnum,ITask>;

    并且工作正常 - 我在MoveNext方法中检查了它们并且能够进行有效移动 - 问题是,通过这种方法,我无法创建场景,其中我需要为1个状态提供多个任务

  7. 我也试图尝试
  8. 的声明

    StateTransition transition = new StateTransition(CurrentState,task);

    在State类的MoveNext方法中 - 例如,如果我放置对象&#34; resume&#34; (之前创建的是为了将其添加到字典中)而不是&#34; task&#34;参数,它正在工作 - 因为我基本比较了2个相同的对象。但是,正如您所看到的,我还尝试定义对象

    ITask resumenew = new ResumeTask();

    再次传递而不是&#34;任务&#34;参数 - 它无法正常工作。

    总结一下 - 这是一种非常糟糕的做法,还是我某处有一些小错误,我不知道? 我希望这个问题不会太混乱 - 如果有任何问题,我可以编辑或回答评论。谢谢你的帮助。


    修改 如果我按原样保留其余部分,只需更改State类:

    class State
    {
    
    
    
    
        public StateEnum CurrentState;
    
        Dictionary<ITask, StateEnum> transitions;
    
        ITask pause = new PauseTask();
        ITask resume = new ResumeTask();
    
        public State()
        {
    
            CurrentState = StateEnum.Pending;
            transitions = new Dictionary<ITask, StateEnum>
            {
                {pause, StateEnum.Pending },
                {resume, StateEnum.Processing }
            };
        }
    
    
        public StateEnum MoveNext(ITask task)
        {
            StateEnum nextState;
            if (!transitions.TryGetValue(task, out nextState))
            {
                return StateEnum.Error;
            }
            else
            {
                return nextState;
            }
        }
    
    }
    

    它正在工作 - 如果state是StateEnum.Pending并且我在MoveNext()方法中传递任务ResumeTask resumetask = new ResumeTask(),它将返回StateEnum.Processing,这是正确的。

    所以&#34;简单&#34;对象键字典正在工作,但是当我将该对象封装到另一个对象中时,尽管再次覆盖了Equals和GetHashCode,但我无法获得匹配(该实现显示在主post-State类中)。

    问题是,如果我基本上传递同一类的对象,为什么我不能得到匹配。


    EDIT2:

    这对于我需要的目的来说太复杂了。我尝试了使用List<KeyValuePair<Enum,Object>>的不同方法,因为我不需要在创建字典后更改字典,并且列表对于更多值没有相同键的问题。到目前为止,它正在发挥作用。

    如果需要,我可以发布最终代码。

0 个答案:

没有答案