长时间进程的报告/监控进度的设计模式

10

有人可以为长时间进程的报告/监控状态/进度建议一个好的设计模式。 基本上,我有一个接收“数据上下文”对象的代码库:

public class DataContext : IDataContext
{
    pulbic Dictionary<string, objects> Properties { get; private set; }

    // Additional properties removed for simplicity...
}

根据提供的上下文,创建一个任务对象(非TPL-任务),其中包含各种子任务。在执行过程中,DataContext对象传递给各个子任务,以便检索或更新它。
例如,假设主任务是“复制文件”任务。DataContext将具有属性,如SourceFolder和TargetFolder,可能还有一个FilterFiles属性(例如*.docx)。我们的主任务将是CopyFilesTasks,并且它将具有子任务的“管道”——扫描文件夹、扫描文件、过滤文件、复制文件等等...
我正在寻找的是允许任务/子任务向调用者/执行者报告其进度的最佳方法。在我们上面的示例中,进度的变化可能只是“已复制文件ABC.docx...”,或者可能是更加“复杂”的东西,如“正在扫描文件夹XYZ...”
我考虑了以下选项:
  1. INotifyPropertyChanged: 在DataContext中添加一个"Progress"属性。

    public string Progress { get; set { _progress = value; RaisePropertyChanged("Progress"); }

    并且由创建DataContext对象的代码注册到PropertyChanged事件。然而,这似乎是一个过于简单化的方法...

  2. ILog(使用您喜欢的任何日志记录框架):在各种任务/子任务中使用ILog实例,并让主任务执行者将自己的监听器添加到日志记录框架中。 然而,这似乎是弯曲了日志记录机制去做它不应该做的事情。

  3. Udi Dahan的DomainEvents:任务的执行者可以将DataContext视为一个"领域",因此我们可以尝试为"ProgressChanged"事件实现一个"EventHandler"。理论上,这甚至可以用于更精细的事件,发生在特定的子任务中...但再次,这感觉像是强制概念...

我的担忧包括:

  • 进度可能不是唯一需要监视的“事件” - 在我们上面的示例中,我们可能希望更加明确定义,例如FolderHandled,FileCopied等,但是在执行任务时可能不知道确切的事件(请记住 - 子任务是基于DataContext创建的,可能会导致执行不同的任务)。
  • 运行任务的上下文尚未定义。目前,我只计划从命令行应用程序运行任务,因此需要将输出发送到命令行以进行调试。稍后,当我将其移动到服务时,我可能希望有一个“监听器”使用任务的进度更新数据库(例如)。
2个回答

2
你可以为每种可能的操作类型声明参数,比如文件操作的FileOperationEventArgs,数据库操作的DatabaseUpdateEventArgs等。
public class FileOperationEventArgs : EventArgs
{
    public readonly string SourceFolder;
    public readonly string TargetFolder;

    public FileOperationEventArgs(string sourceFolder, string targetFolder)
    {
        SourceFolder = sourceFolder;
        TargetFolder = targetFolder;
    }
}

public class DatabaseUpdateEventArgs : EventArgs
{
    public readonly int RowsUpdated;

    public DatabaseUpdateEventArgs(int rowsUpdated)
    {
        RowsUpdated = rowsUpdated;
    }
}

OperationProgress类为每种操作类型声明事件。

public class OperationProgress
{
    public event EventHandler<FileOperationEventArgs> FileCopied;
    public event EventHandler<DatabaseUpdateEventArgs> DatabaseUpdated;

    public void OnFileCopied(FileOperationEventArgs a)
    {
        if(FileCopied != null)
            FileCopied(this, a);
    }

    public void OnDatabaseUpdated(DatabaseUpdateEventArgs a)
    {
        if (DatabaseUpdated != null)
            DatabaseUpdated(this, a);
    }
}

创建DataContext时将指定OperationProgress。
public class DataContext : IDataContext
{
    public Dictionary<string, object> Properties { get; private set; }
    public OperationProgress Progress { get; private set; }

    public DataContext(OperationProgress progress)
    {
        Progress = progress;
    }
}

子任务的实现可以更新进度。
public class FileCopySubTask
{
    public void Execute(DataContext context)
    {
        context.Progress.OnFileCopied(new FileOperationEventArgs("c:/temp1", "c:/temp2"));
    }
}

这与Udi Dahan的DomainEvents类似,但更受限制 - 它只限制于特定“已知”事件 - 对于新任务和新事件,我需要编译所有内容... 这也意味着如果我有多个任务和多个“侦听器”,我将不得不管理事件的注册/注销和引用... - SaguiItay

-2

这不是我需要的 - 我在后台线程中运行代码没有问题...我正在寻找一个更"完整"的解决方案,而不仅仅是如何更新UI中的进度条(顺便说一下,我现在甚至还没有UI,也可能永远不会有)。 - SaguiItay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接