防止将重复对象添加到 List<object>,同时保留具有两个同名对象的能力?

Prevent duplicate objects being added to List<object> while retaining the ability to have two object of the same name?

我已经尝试了一遍又一遍,但我现在只是在兜圈子。

我在外部存储了一组大部分独特的作业文件,我从这些文件中收集信息并通过列表将其存储在我的程序中。

有时,我有两个同名的作业文件(不幸的是,这是不可避免的)但包含不同的数据(其中最独特的是 DateTime 字符串)。

我的程序通过轮询这些文件的 3 个位置(所有位置都是镜像的,因此每个位置都存在相同的数据)来工作,收集信息,然后根据当前状态将信息输出到 ListView window每个作业文件。

我遇到的问题是防止将重复的条目添加到我的列表中,导致列表中只有 23 个作业文件有 69 个对象。

为了避免在列表视图中出现重复输出,我尝试使用字典来存储基于作业文件名的已知键,但是当到达与现有条目同名的第二个文件时,这会失败。结果我在列表中只看到 21 个工作,本应包含 23 个工作(我也抛出了异常)。我通过在第二个条目的末尾附加一些内容来解决这个问题,但这并不理想,后来发现会导致其他并发症。

有什么想法吗?

这是我目前所拥有的。

public List<object> PendingJobsArray = new List<object>();
public List<object> ActiveJobsArray = new List<object>();
public List<object> CompletedJobsArray = new List<object>();

public JobObject PendingJobs = new JobObject();
public JobObject ActiveJobs = new JobObject();
public JobObject CompletedJobs = new JobObject();

    private void updatePending(int index, XmlParser xmlParser)
    {
        if (Program.PendingJobsArray.Count == 0)
        {
            Program.KnownPendingJobs.Add(xmlParser.getElementAttrValue(index, "Name"), xmlParser.getElementAttrValue(index, "DateTime"));
            JobObject PendingJobs = new JobObject();
            PendingJobs.jobObjectName = xmlParser.getElementAttrValue(index, "Name");
            PendingJobs.jobObjectState = xmlParser.getElementAttrValue(index, "State");
            PendingJobs.jobObjectDiscName = xmlParser.getElementAttrValue(index, "DiscName");
            PendingJobs.jobObjectPercentComplete = Convert.ToInt32(xmlParser.getElementAttrValue(index, "TotalPercentComplete"));
            PendingJobs.jobObjectDateTime = xmlParser.getElementAttrValue(index, "DateTime");
            PendingJobs.jobObjectRequested = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Requested"));
            PendingJobs.jobObjectCompleted = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Completed"));
            PendingJobs.jobObjectFailed = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Failed"));
            PendingJobs.jobObjectPriority = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Priority"));
            // PendingJobs.jobObjectServer = xmlParser.getElementAttrValue("Server");
            // PendingJobs.jobObjectOperation = xmlParser.getElementAttrValue("Operation");
            Program.PendingJobsArray.Add(PendingJobs);
        }
        else if (Program.KnownPendingJobs.ContainsKey(xmlParser.getElementAttrValue(index, "Name")))
        {
            for (int i = 0; i < Program.PendingJobsArray.Count; ++i)
            {
                if (xmlParser.getElementAttrValue(index, "State") == "Write")
                {
                    Program.PendingJobsArray.RemoveAt(index);
                }
                else
                {
                    PendingJobs.jobObjectName = xmlParser.getElementAttrValue(index, "Name");
                    PendingJobs.jobObjectState = xmlParser.getElementAttrValue(index, "State");
                    PendingJobs.jobObjectDiscName = xmlParser.getElementAttrValue(index, "DiscName");
                    PendingJobs.jobObjectPercentComplete = Convert.ToInt32(xmlParser.getElementAttrValue(index, "TotalPercentComplete"));
                    PendingJobs.jobObjectDateTime = xmlParser.getElementAttrValue(index, "DateTime");
                    PendingJobs.jobObjectRequested = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Requested"));
                    PendingJobs.jobObjectCompleted = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Completed"));
                    PendingJobs.jobObjectFailed = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Failed"));
                    PendingJobs.jobObjectPriority = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Priority"));
                    Program.PendingJobsArray[index] = PendingJobs;
                }
            }
        }
        else if (Program.KnownPendingJobs.ContainsKey(xmlParser.getElementAttrValue(index, "Name")))
        }
        else
        {
            Program.KnownPendingJobs.Add(xmlParser.getElementAttrValue(index, "Name"), xmlParser.getElementAttrValue(index, "DateTime"));
            JobObject PendingJobs = new JobObject();
            PendingJobs.jobObjectName = xmlParser.getElementAttrValue(index, "Name");
            PendingJobs.jobObjectState = xmlParser.getElementAttrValue(index, "State");
            PendingJobs.jobObjectDiscName = xmlParser.getElementAttrValue(index, "DiscName");
            PendingJobs.jobObjectPercentComplete = Convert.ToInt32(xmlParser.getElementAttrValue(index, "TotalPercentComplete"));
            PendingJobs.jobObjectDateTime = xmlParser.getElementAttrValue(index, "DateTime");
            PendingJobs.jobObjectRequested = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Requested"));
            PendingJobs.jobObjectCompleted = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Completed"));
            PendingJobs.jobObjectFailed = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Failed"));
            PendingJobs.jobObjectQuantity = xmlParser.getElementAttrValue(index, "Quantity");
            PendingJobs.jobObjectPriority = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Priority"));
            //PendingJobs.jobObjectServer = xmlParser.getElementAttrValue("Server");
            //PendingJobs.jobObjectOperation = xmlParser.getElementAttrValue("Operation");
            Program.PendingJobsArray.Add(PendingJobs);
        }
    }

更新 代码基于下面的评论,

    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Collections;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    using System.Windows.Forms;

    namespace SOERequestProgress
    {
        class XmlSplitter
        {
            // Declarations
            private static string[] COMPLETED_STATES = new string[2]
        {
          "ERROR",
          "COMPLETE"
        };

            private static string[] PENDING_STATES = new string[1]
        {
          "PENDING"
        };

            private static string[] ACTIVE_STATES = new string[1]
        {
          "PAUSED"
        };

            private const string STATE_ERROR = "ERROR";
            private const string STATE_COMPLETE = "COMPLETE";
            private const string STATE_PENDING = "PENDING";
            private const string STATE_ACTIVE = "PAUSED";

            public static JobObject PendingJobs = new JobObject();
            public static JobObject CompletedJobs = new JobObject();
            public static JobObject ActiveJobs = new JobObject();

            //public static JobObject x;

            public static int intI = 0;

            // Add additional info from parsed XML (Currently only "Name" and "State" are collected.
            public static void splitXml(string JobList, out List<JobObject> Active, out List<JobObject> Completed, out List<JobObject> Pending)
            {
                bool flag = false;
                int num1 = 0;
                string text = "";
                string xmlString = "";
                while (!flag)
                {
                    if (num1 < 3)
                    {
                        try
                        {
                            xmlString = JobList;
                            flag = true;
                        }
                        catch (Exception ex)
                        {
                            ++num1;
                            text = text + "Try (" + num1.ToString() + ") " + ex.Message + "\n";
                            Thread.Sleep(1000);
                        }
                    }
                    else
                        break;
                }
                if (!flag)
                {
                    int num2 = (int)MessageBox.Show(text, "Job list error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                }
                else
                {
                    XmlParser xmlParser = new XmlParser();
                    if (!xmlParser.setXmlString(xmlString))
                    {
                        int num3 = (int)MessageBox.Show("Error parsing job list server response.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                        flag = false;
                    }
                    else
                    {
                        int num3 = xmlParser.setElementName("Job");
                        for (int index = 0; index < num3; ++index)
                        {
                            string elementAttrValue1 = xmlParser.getElementAttrValue(index, "Name");
                            string elementAttrValue2 = xmlParser.getElementAttrValue(index, "State");
                            if (isState(elementAttrValue2, PENDING_STATES))
                            {
                                updatePending(index, xmlParser);
                            }
                            else if (isState(elementAttrValue2, COMPLETED_STATES))
                            {
                                updateCompleted(index, xmlParser);
                            }
                            else //if (isState(elementAttrValue2, ACTIVE_STATES))
                            {
                                updateActive(index, xmlParser);
                            }
                        }
                    }
                }
                Active = Program.ActiveJobsArray;
                Completed = Program.CompletedJobsArray;
                Pending = Program.PendingJobsArray;
            }

            private static void updatePending(int index, XmlParser xmlParser)
            {
                var jobName = xmlParser.getElementAttrValue(index, "Name");
                var pendingJob = Program.PendingJobsArray.Find(x => x.jobObjectName == jobName);

                if (pendingJob == null)
                {
                    JobObject newPendingJob = CreateJob("Pending", index, xmlParser);
                    Program.PendingJobsArray.Add(newPendingJob);
                }
            }

            private static void updateCompleted(int index, XmlParser xmlParser)
            {
                var jobName = xmlParser.getElementAttrValue(index, "Name");
                var CompletedJob = Program.CompletedJobsArray.Find(x => x.jobObjectName == jobName);

                if (CompletedJob == null)
                {
                    JobObject newCompletedJob = CreateJob("Completed", index, xmlParser);
                    Program.CompletedJobsArray.Add(newCompletedJob);
                }
            }

            private static void updateActive(int index, XmlParser xmlParser)
            {
                var jobName = xmlParser.getElementAttrValue(index, "Name");
                var activeJob = Program.ActiveJobsArray.Find(x => x.jobObjectName == jobName);

                if (activeJob == null)
                {
                    JobObject newActiveJob = CreateJob("Active", index, xmlParser);
                    Program.ActiveJobsArray.Add(newActiveJob);
                }
            }

            private static JobObject CreateJob(string jobType, int index, XmlParser xmlParser)
            {
                if (jobType == "Pending")
                {
                    JobObject x = new JobObject();
                    x.jobObjectName = xmlParser.getElementAttrValue(index, "Name");
                    x.jobObjectState = xmlParser.getElementAttrValue(index, "State");
                    x.jobObjectDiscName = xmlParser.getElementAttrValue(index, "DiscName");
                    x.jobObjectPercentComplete = Convert.ToInt32(xmlParser.getElementAttrValue(index, "TotalPercentComplete"));
                    x.jobObjectDateTime = xmlParser.getElementAttrValue(index, "DateTime");
                    x.jobObjectRequested = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Requested"));
                    x.jobObjectCompleted = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Completed"));
                    x.jobObjectFailed = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Failed"));
                    x.jobObjectQuantity = xmlParser.getElementAttrValue(index, "Quantity");
                    x.jobObjectPriority = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Priority"));
                    //x.jobObjectServer = xmlParser.getElementAttrValue("Server");
                    //x.jobObjectOperation = xmlParser.getElementAttrValue("Operation");
                    return x;
                }
                if (jobType == "Completed")
                {
                    JobObject x = new JobObject();
                    x.jobObjectName = xmlParser.getElementAttrValue(index, "Name");
                    x.jobObjectState = xmlParser.getElementAttrValue(index, "State");
                    x.jobObjectDiscName = xmlParser.getElementAttrValue(index, "DiscName");
                    x.jobObjectPercentComplete = Convert.ToInt32(xmlParser.getElementAttrValue(index, "TotalPercentComplete"));
                    x.jobObjectDateTime = xmlParser.getElementAttrValue(index, "DateTime");
                    x.jobObjectRequested = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Requested"));
                    x.jobObjectCompleted = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Completed"));
                    x.jobObjectFailed = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Failed"));
                    //x.jobObjectServer = xmlParser.getElementAttrValue("Server");
                    //x.jobObjectOperation = xmlParser.getElementAttrValue("Operation");
                    return x;
                }

                if (jobType == "Active")
                {
                    JobObject x = new JobObject();
                    x.jobObjectName = xmlParser.getElementAttrValue(index, "Name");
                    x.jobObjectState = xmlParser.getElementAttrValue(index, "State");
                    x.jobObjectDiscName = xmlParser.getElementAttrValue(index, "DiscName");
                    x.jobObjectPercentComplete = Convert.ToInt32(xmlParser.getElementAttrValue(index, "TotalPercentComplete"));
                    x.jobObjectDateTime = xmlParser.getElementAttrValue(index, "DateTime");
                    x.jobObjectRequested = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Requested"));
                    x.jobObjectCompleted = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Completed"));
                    x.jobObjectFailed = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Failed"));
                    x.jobObjectPriority = Convert.ToInt32(xmlParser.getElementAttrValue(index, "Priority"));
                    //x.jobObjectServer = xmlParser.getElementAttrValue("Server");
                    //x.jobObjectOperation = xmlParser.getElementAttrValue("Operation");
                    return x;
                }
                return null;
            }

            private static bool isState(string jobState, string[] knownStates)
            {
                bool flag = false;
                for (int index = 0; index < knownStates.Length; ++index)
                {
                    if (jobState.ToUpper().Equals(knownStates[index]))
                    {
                        flag = true;
                        //break;
                    }
                }
                return flag;
            }
        }
    }

这个新代码似乎不正确,我看不出它在哪里失败,但它在几秒钟内用 200 多个条目填充了我的 CompletedJobArray。

我的 ListView 仅显示 1 个条目(针对唯一作业进行过滤)并且在检查数组的内容时,它为所有 200 多个条目添加了相同的 jobObject。

谁能找出这段代码中的缺陷?

更新 2: IEqualityComparer 已实施,遇到更多错误。

下面的代码是Equals和GetHashCode的实现。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SOERequestProgress
{
    class JobComparer : IEqualityComparer<JobObject>
    {
        public JobComparer(Func<JobObject, object> keySelector)
        {
            KeySelector = keySelector;
        }

        public bool Equals(JobObject x, JobObject y)
        {
            return KeySelector(x).Equals(KeySelector(y));
                //x.jobObjectName == y.jobObjectName &&
                //x.jobObjectDateTime == y.jobObjectDateTime;
        }

        public int GetHashCode(JobObject job)
        {
             return KeySelector(job).GetHashCode();
        }
    }
}

此实现抛出以下错误,

Error   1   'SOERequestProgress.JobObject' does not implement interface member 'System.Collections.Generic.IEqualityComparer<SOERequestProgress.JobComparer>.GetHashCode(SOERequestProgress.JobComparer)'   C:\Users\youngs\Documents\Visual Studio 2012\Projects\SOERequestProgress\SOERequestProgress\SOERequestProgress\JobObject.cs 9   11  SOERequestProgress

Error   2   'SOERequestProgress.JobObject' does not implement interface member 'System.Collections.Generic.IEqualityComparer<SOERequestProgress.JobComparer>.Equals(SOERequestProgress.JobComparer, SOERequestProgress.JobComparer)'    C:\Users\youngs\Documents\Visual Studio 2012\Projects\SOERequestProgress\SOERequestProgress\SOERequestProgress\JobObject.cs 9   11  SOERequestProgress

更新 3: 好吧,我几乎要认输了,因为我似乎无法理解 IEqualityComparer 是如何工作的……而且我又开始敲键盘了 >.<

下面的代码现在在 CompletedJobsArray 中获得了 72 个作业,这相当于 24 个作业重复了 3 次!!!

private static void updateCompleted(int index, XmlParser xmlParser)
        {
            var jobName = xmlParser.getElementAttrValue(index, "Name");
            var jobDate = xmlParser.getElementAttrValue(index, "DateTime");
            // Commented line below has same affect as uncommented line, except it always returns true....
            //var CompletedJobs = Program.CompletedJobsArray.Distinct(new JobComparer(x => new { x.jobObjectName, x.jobObjectDateTime }));
            var CompletedJobs = Program.CompletedJobsArray.Find(x=>x.Equals(jobDate));

            if (CompletedJobs == null)
            {
                JobObject newCompletedJob = CreateJob("Completed", index, xmlParser);
                Program.CompletedJobsArray.Add(newCompletedJob);
            }
            else
            {
                // Code below causes issues with IEnumerable
                //UpdateJob("Completed", index, CompletedJobs, xmlParser);
            }
        }

我有 24 个作业,但是当对这些作业文件的 3 个位置进行轮询时,我只需要将 24 个唯一的作业添加到数组中....我做错了什么?

更新 4重复仍然出现...但不在列表中...

好的,再深入一点,我发现我的列表包含正确数量的作业,没有出现重复。

但是,当新工作进入列表时,程序的输出(在 UI 中)会针对某些工作而不是所有工作进行复制。

我似乎无法确定其中的原因,因为我试图让事情尽可能简单,并且正在使用一个列表(已确认按预期工作)并将我的输出生成到那里的列表视图。

这里是有问题的代码部分,

private void SortViews()
{
    var Jobs = Program.JobsArray;
    Program.JobsArray.Sort((a, b) => String.Compare(a.jobObjectDateTime, b.jobObjectDateTime));
    if (Jobs.Count >= 0)
    {
        foreach (JobObject Job in Jobs.Where(x => PENDING_STATES.Contains(x.jobObjectState)))
        {
            if (Job.inPendingView && Job.inPendingView)
            {
                Job.inCompletedView = false;
                CompletedJobsView.Items.Remove(PendingJobsView.FindItemWithText(Job.jobObjectName));
                Job.inActiveView = false;
                ActiveJobsView.Items.Remove(ActiveJobsView.FindItemWithText(Job.jobObjectName));
                ListViewItem item = PendingJobsView.FindItemWithText(Job.jobObjectDateTime);
                item.SubItems[0].Text = Job.jobObjectName;
                item.SubItems[1].Text = Convert.ToString(Job.jobObjectPriority);
                item.SubItems[2].Text = Job.jobObjectDiscName;
                item.SubItems[3].Text = Convert.ToString(Job.jobObjectRequested);
                item.SubItems[4].Text = Job.jobObjectDateTime;
            }
            else
            {
                string[] brr = new string[6];
                ListViewItem item;
                brr[0] = Job.jobObjectName;
                brr[1] = Convert.ToString(Job.jobObjectPriority);
                brr[2] = Job.jobObjectDiscName;
                brr[3] = Convert.ToString(Job.jobObjectRequested);
                brr[4] = Job.jobObjectDateTime;
                item = new ListViewItem(brr);
                item.ForeColor = Color.Blue;
                PendingJobsView.Items.Add(item);
                Job.inPendingView = true;
                Job.inActiveView = false;
                Job.inCompletedView = false;
                Job.isActive = false;
                Job.isCompleted = false;
                Job.isPending = true;
            }
        }

        foreach (JobObject Job in Jobs.Where(x => ACTIVE_STATES.Contains(x.jobObjectState)))
        {
            if (Job.isActive && Job.inActiveView)
            {
                Job.inPendingView = false;
                PendingJobsView.Items.Remove(PendingJobsView.FindItemWithText(Job.jobObjectName));
                Job.inCompletedView = false;
                CompletedJobsView.Items.Remove(CompletedJobsView.FindItemWithText(Job.jobObjectDateTime));
                //ActiveJobsView.Refresh();
                ListViewItem item = ActiveJobsView.FindItemWithText(Job.jobObjectName);
                item.SubItems[0].Text = Job.jobObjectName;
                item.SubItems[1].Text = Convert.ToString(Job.jobObjectPriority);
                item.SubItems[2].Text = Job.jobObjectDiscName;
                item.SubItems[3].Text = Convert.ToString(Job.jobObjectCompleted) + " of " + Convert.ToString(Job.jobObjectRequested);
                item.SubItems[4].Text = Convert.ToString(Job.jobObjectFailed);
                item.SubItems[5].Text = Convert.ToString(Job.percentComplete) + "%";
                item.SubItems[6].Text = Convert.ToString(Job.jobObjectState);
            }
            else
            {
                Job.isActive = true;
                string[] crr = new string[7];
                ListViewItem item;
                crr[0] = Job.jobObjectName;
                crr[1] = Convert.ToString(Job.jobObjectPriority); 
                crr[2] = Job.jobObjectDiscName;
                crr[3] = Convert.ToString(Job.jobObjectCompleted) + " of " + Convert.ToString(Job.jobObjectRequested);
                crr[4] = Convert.ToString(Job.jobObjectFailed);
                crr[5] = Convert.ToString(Job.percentComplete) + "%";
                crr[6] = Convert.ToString(Job.jobObjectState);
                item = new ListViewItem(crr);
                item.ForeColor = Color.DarkOrange;
                ActiveJobsView.Items.Add(item);
                Job.inActiveView = true;
                Job.inPendingView = false;
                Job.inCompletedView = false;
                Job.isActive = true;
                Job.isCompleted = false;
                Job.isPending = false;
            }
        }

        foreach (JobObject Job in Jobs.Where(x => COMPLETED_STATES.Contains(x.jobObjectState)))
        {
            if (Job.isCompleted && Job.inCompletedView)
            {
                Job.inPendingView = false;
                PendingJobsView.Items.Remove(PendingJobsView.FindItemWithText(Job.jobObjectName));
                Job.inActiveView = false;
                ActiveJobsView.Items.Remove(ActiveJobsView.FindItemWithText(Job.jobObjectName));
                //CompletedJobsView.Refresh();
                ListViewItem item = CompletedJobsView.FindItemWithText(Job.jobObjectName);
                item.SubItems[0].Text = Job.jobObjectName;
                item.SubItems[1].Text = Job.jobObjectDiscName;
                item.SubItems[2].Text = Convert.ToString(Job.jobObjectCompleted) + " of " + Convert.ToString(Job.jobObjectRequested);
                item.SubItems[3].Text = Convert.ToString(Job.jobObjectFailed);
                item.SubItems[4].Text = Convert.ToString(Job.jobObjectState);
                item.SubItems[5].Text = Job.jobObjectDateTime;
            }
            else
            {
                string[] arr = new string[6];
                ListViewItem item;
                arr[0] = Job.jobObjectName;
                arr[1] = Job.jobObjectDiscName;
                arr[2] = Convert.ToString(Job.jobObjectCompleted) + " of " + Convert.ToString(Job.jobObjectRequested);
                arr[3] = Convert.ToString(Job.jobObjectFailed);
                arr[4] = Convert.ToString(Job.jobObjectState);
                arr[5] = Job.jobObjectDateTime;
                item = new ListViewItem(arr);
                if (Job.jobObjectState == "ERROR")
                {
                    item.ForeColor = Color.Firebrick;
                }
                if (Job.jobObjectState == "COMPLETE")
                {
                    item.ForeColor = Color.Green;
                }
                CompletedJobsView.Items.Add(item);
                Job.inCompletedView = true;
                Job.inPendingView = false;
                Job.inActiveView = false;
                Job.isCompleted = true;
                Job.isActive = false;
                Job.isPending = false;
            }
        }   
    }
}

任何想法是什么导致了这种行为?

再次感谢:)

为您的 PendingJobs 对象定义自定义 IEqualityComparer。然后,您可以根据需要轻松调整比较,并比较所有字段或字段的子集。然后你可以创建一个 HashSet 并将其提供给这个比较器。如果更好,您也可以使用字典,因为它也接受 IEqualityComparer。

与其让代码复杂化,不如在这里使用单个列表更容易。

List<JobObject> jobs = new List<JobObject>();

// Code that adds / updates a job
var newJob = CreateJob(state);
// The equality comparer should check for a job name and job date of two jobs to ensure the uniqueness
var existingJob = jobs.Find(x => x.Equals(x, newJob));

if(existingJob != null)
{
  // Update your existing job
  // If you want to calulate the time interval between job start till end, you can have more properties
  // indicating the jobPendingStartTime, jobActiveStartTime etc.
}
else
{
  jobs.Add(newJob);  
}

// Code to find jobs
var pendingJobs = jobs.Where(x => PENDING_STATES.contains(x.jobObjectState));
var activeJobs = jobs.Where(x => ACTIVE_STATES.contains(x.jobObjectState));
var completedJobs = jobs.Where(x => COMPLETED_STATES.contains(x.jobObjectState));

// Bind to different list views

IEqualityComparer 实现:

public class JobObject
{
    public string Name { get; set; }

    public string Date { get; set; }
    //Other properties
}

public class JobObjectComparer : IEqualityComparer<JobObject>
{        
    public bool Equals(JobObject x, JobObject y)
    {
        return x.Name == y.Name &&
               x.Date == y.Date;
    }

    public int GetHashCode(JobObject job)
    {
        return job.GetHashCode();
    }

    // Then use it as follows.
    // JobObject newJob = CreateJob();
    // var comparer = new JobObjectComparer();
    // var existingJob = jobsArray.Find(x => comparer.Equals(x, newJob));        
    // if(existingJob != null)
    // { 
    //   Job Exists
    // }
}

如果有帮助请告诉我。