gpt4 book ai didi

c# - 在任务中报告/记录

转载 作者:太空宇宙 更新时间:2023-11-03 21:32:33 24 4
gpt4 key购买 nike

如果给定的记录处理失败,我有一个异步调用会抛出异常。该异常作为聚合异常被捕获。现在,我必须从我的异步方法中记录一条警告消息。我无法登录到 TextBox/Grid,因为它不允许访问不同线程的控件,而且我无法抛出异常,因为我实际上想记录并继续该任务。这是启动任务的父代码:

private List<OrganizationUser> GenerateDataList(string importFilePath, int lastUserId = -1)
{
var resultList = new List<OrganizationUser>();

// Note: ReadLine is faster than ReadAllLines
var lineCount = File.ReadLines(importFilePath).Count();
LogMessage(new LogEntry(String.Format(" - File has {0} lines.", lineCount)));
var consistancyCounter = 0;

ResetProgress();

using (var fs = File.Open(importFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (var bs = new BufferedStream(fs))
{
using (var sr = new StreamReader(bs))
{
string readLine;
while ((readLine = sr.ReadLine()) != null)
{
if (string.IsNullOrEmpty(readLine) || readLine == "---EOF---")
{
break;
}

try
{
var processLineTask = Task.Run(() => GenerateDataListInternal(nextId++, localReadLine, localConsistancyCounter));
processLineTask.Wait();

var result = processLineTask.Result;

if (result != null)
{
resultList.Add(result);
}
}
catch (AggregateException exp)
{
if (exp.InnerExceptions.Count == 1 && exp.InnerExceptions.Any(x => x is DataFileBadColumnNumbers || x is DataFileGenerateListException))
{
LogMessage(new LogEntry(exp.InnerExceptions[0].Message, LogEntryType.Warning));
}
else if (exp.InnerExceptions.Count == 1 && exp.InnerExceptions.Any(x => x is IndexOutOfRangeException))
{
LogMessage(new LogEntry(String.Format(" - Data cannot be parsed at line #{0}. Data is: {1}", localConsistancyCounter + 1, localReadLine), LogEntryType.Warning));
}
else
{
throw;
}
}
}

if (ProgressBarImport.Value <= ProgressBarImport.Maximum)
{
ProgressBarImport.PerformStep();
}
}
}
}
}

上面代码中,GenerateDataListInternal是抛出异常的方法,现在需要记录。

如何从 GenerateDataListInternal 方法中登录?我已经尝试过委托(delegate)方法,只是挂起应用程序。我有一个记录到控制台、网格和文本文件(按此顺序)的方法。由于跨线程操作,从异步方法对该方法的任何调用都会失败。

最佳答案

这已经通过 System.IProgress 提供了接口(interface)和 Progress类,其中 T可以是任何类(class),让您报告的不仅仅是简单的进度百分比。

IProgress<T>.Report允许您从异步操作内部报告进度(或其他任何内容),而不必担心谁将实际处理报告。

Progress<T>每当您的任务调用 .Report 时,将在创建它的线程(例如 UI 线程)上调用一个操作和/或引发一个事件。

这个例子来自.NET Framework Blog显示使用起来有多么容易 IProgress<T> :

async Task<int> UploadPicturesAsync(List<Image> imageList, IProgress<int> progress)
{
int totalCount = imageList.Count;
int processCount = await Task.Run<int>(() =>
{
int tempCount = 0;
foreach (var image in imageList)
{
//await the processing and uploading logic here
int processed = await UploadAndProcessAsync(image);
if (progress != null)
{
progress.Report((tempCount * 100 / totalCount));
}
tempCount++;
}

return tempCount;
});
return processCount;
}

异步进程从这段代码开始:

private async void Start_Button_Click(object sender, RoutedEventArgs e)
{
//construct Progress<T>, passing ReportProgress as the Action<T>
var progressIndicator = new Progress<int>(ReportProgress);
//call async method
int uploads=await UploadPicturesAsync(GenerateTestImages(), progressIndicator);
}

请注意 progressIndicator在 UI 线程中创建,所以 ReportProgress方法将在 UI 线程上调用。

更新

从评论来看,您似乎正在尝试创建自己的日志记录解决方案,但在从多个线程访问日志文件时遇到了问题。

这里最好的解决方案是使用像 log4net 这样的日志库, NLog甚至.NET 的诊断类。所有这些都可以在多线程下正常工作。

IProgress<T>在这里仍然可以提供帮助,因为处理 Report 事件的委托(delegate)可以简单地将消息写入您已经在 UI 线程上创建的日志文件。

你可以这样写:

var progress = new Progress<LogEntry>(entry =>
{
_logFile.WriteLine("{0} : {1}",entry.EntryType,entry.Message);
});

并从任务内部报告:

var entry=new LogEntry(...);
progress.Report(entry);

关于c# - 在任务中报告/记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23518593/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com