在以下场景中如何将自定义对象映射到相应的任务?
How to map the custom object with corresponding Task in the following scenario?
我正在开发一个控制台应用程序,其中我有一个第三方休息客户端(准确地说是 wordpress 休息客户端),它有一些方法与 return Task
对象。一个示例方法签名可以是这样的:
public Task<bool> Delete(int id);
我有一个要删除的 Post
列表。我可以简单地做一些事情:
public void DeleteGivenPosts(List<Post> posts) {
posts.ForEach(async post => await wpRestClient.Delete(post.Id));
}
在这种情况下,删除是即刻完成的。如果我记录有关删除的 post 的信息会更好。日志语句如:
logger.Log($"A post with {post.Id} is deleted");
所以,我决定计划任务。
public async Task DeleteGivenPosts(List<Post> posts) {
var postDeletionTasks = posts.Select(post => wpRestClient.Delete(post.Id));
foreach (var deletionTask in TaskExtensionUtil.GetTasksInCompletingOrder(postsDeletionTasks)) {
bool deletionResult = await deletionTask;
if(deletionResult) {
//i want to log success of deletion here
} else {
//i want to log the failure of deletion here
}
}
}
这里 TaskExtensionUtil.GetTasksInCompletingOrder()
是一个辅助方法,它 return 按任务完成的顺序排列任务。代码是:
public static List<Task<T>> GetTasksInCompletingOrder<T>(IEnumerable<Task<T>> sourceTasks) {
var sourceTasksArr = sourceTasks.ToArray();
var taskCompletionSourceArr = new TaskCompletionSource<T>[sourceTasksArr.Length];
var currentSlot = -1;
for (int i = 0; i < sourceTasksArr.Length; i++) {
taskCompletionSourceArr[i] = new TaskCompletionSource<T>();
sourceTasksArr[i].ContinueWith(prev => {
int indexToSet = Interlocked.Increment(ref currentSlot);
taskCompletionSourceArr[indexToSet].SetResult(prev.Result);
});
}
return taskCompletionSourceArr.Select(i => i.Task).ToList();
}
问题是 deletionResult
是 bool
。为了记录有关 post 被删除的信息,我需要获取与删除任务关联的 Post
对象。
我想创建一个字典,将删除任务映射到相应的 Post
,方法如下:
posts.Select(post => new { deletionTask = wpRestClient.Delete(post.Id), post})
.ToDictionary(i => i.deletionTask, i => i.post);
但这行不通,因为在 GetTasksInCompletingOrder
中,原始删除任务被转换为 TaskCompletionSource
任务。所以我总是会得到一个例外,即字典中不存在该键。此外,我不确定当字典以 Task
个对象作为键时它会如何表现。
此时我不知道如何实现日志记录。我将不胜感激任何帮助。
删除后如何写入logstatement?
public async Task DeleteGivenPosts(List<Post> posts)
{
await Task.WhenAll(
posts.Select(async post =>
{
bool res = await wpRestClient.Delete(post.Id);
string message = res ? $"Post {post.Id} is deleted" : $"Post {post.Id} survived!";
logger.Log(message);
}));
}
这里有一个小的 LinqPad 程序来举例说明该方法的工作原理:
async void Main()
{
List<Post> postList = Enumerable.Range(1, 12).Select(id => new Post {Id = id}).ToList();
Console.WriteLine("Start Deletion");
await DeleteGivenPosts(postList);
Console.WriteLine("Finished Deletion");
}
public static MyRestClient wpRestClient = new MyRestClient();
// Define other methods and classes here
public async Task DeleteGivenPosts(List<Post> posts)
{
await Task.WhenAll(
posts.Select(async post =>
{
bool res = await wpRestClient.Delete(post.Id);
string message = res ? $"Post {post.Id} is deleted" : $"Post {post.Id} survived!";
Console.WriteLine(message);
}));
}
public static Random rand = new Random(DateTime.Now.Millisecond);
public class MyRestClient
{
public async Task<bool> Delete(int i)
{
return await Task<bool>.Run(() => { Thread.Sleep(400); return rand.Next(1,4) == 1;});
}
}
public class Post
{
public int Id { get; set; }
}
输出:
Start Deletion
Post 1 is deleted
Post 3 survived!
Post 5 survived!
Post 6 survived!
Post 2 survived!
Post 4 survived!
Post 8 survived!
Post 7 survived!
Post 9 survived!
Post 11 survived!
Post 10 is deleted
Post 12 is deleted
Finished Deletion
你也可以用你自己的方法包装它,像这样:
IEnumerable<Task<DeletionResult>> postDeletionTasks = posts.Select(post => DeletePost(post.Id));
您的方法和结果 class 可能类似于:
private async Task<DeletionResult> DeletePost(int postId)
{
bool result = await wpRestClient.Delete(postId);
return new DeletionResult(result, postId);
}
和
public class DeletionResult
{
public DeletionResult(bool result, int postId)
{
Result = result;
PostId = postId;
}
public bool Result { get; }
public int PostId { get; }
}
这样你就会得到一个任务列表,结果包含它所影响的 PostId
。
我正在开发一个控制台应用程序,其中我有一个第三方休息客户端(准确地说是 wordpress 休息客户端),它有一些方法与 return Task
对象。一个示例方法签名可以是这样的:
public Task<bool> Delete(int id);
我有一个要删除的 Post
列表。我可以简单地做一些事情:
public void DeleteGivenPosts(List<Post> posts) {
posts.ForEach(async post => await wpRestClient.Delete(post.Id));
}
在这种情况下,删除是即刻完成的。如果我记录有关删除的 post 的信息会更好。日志语句如:
logger.Log($"A post with {post.Id} is deleted");
所以,我决定计划任务。
public async Task DeleteGivenPosts(List<Post> posts) {
var postDeletionTasks = posts.Select(post => wpRestClient.Delete(post.Id));
foreach (var deletionTask in TaskExtensionUtil.GetTasksInCompletingOrder(postsDeletionTasks)) {
bool deletionResult = await deletionTask;
if(deletionResult) {
//i want to log success of deletion here
} else {
//i want to log the failure of deletion here
}
}
}
这里 TaskExtensionUtil.GetTasksInCompletingOrder()
是一个辅助方法,它 return 按任务完成的顺序排列任务。代码是:
public static List<Task<T>> GetTasksInCompletingOrder<T>(IEnumerable<Task<T>> sourceTasks) {
var sourceTasksArr = sourceTasks.ToArray();
var taskCompletionSourceArr = new TaskCompletionSource<T>[sourceTasksArr.Length];
var currentSlot = -1;
for (int i = 0; i < sourceTasksArr.Length; i++) {
taskCompletionSourceArr[i] = new TaskCompletionSource<T>();
sourceTasksArr[i].ContinueWith(prev => {
int indexToSet = Interlocked.Increment(ref currentSlot);
taskCompletionSourceArr[indexToSet].SetResult(prev.Result);
});
}
return taskCompletionSourceArr.Select(i => i.Task).ToList();
}
问题是 deletionResult
是 bool
。为了记录有关 post 被删除的信息,我需要获取与删除任务关联的 Post
对象。
我想创建一个字典,将删除任务映射到相应的 Post
,方法如下:
posts.Select(post => new { deletionTask = wpRestClient.Delete(post.Id), post})
.ToDictionary(i => i.deletionTask, i => i.post);
但这行不通,因为在 GetTasksInCompletingOrder
中,原始删除任务被转换为 TaskCompletionSource
任务。所以我总是会得到一个例外,即字典中不存在该键。此外,我不确定当字典以 Task
个对象作为键时它会如何表现。
此时我不知道如何实现日志记录。我将不胜感激任何帮助。
删除后如何写入logstatement?
public async Task DeleteGivenPosts(List<Post> posts)
{
await Task.WhenAll(
posts.Select(async post =>
{
bool res = await wpRestClient.Delete(post.Id);
string message = res ? $"Post {post.Id} is deleted" : $"Post {post.Id} survived!";
logger.Log(message);
}));
}
这里有一个小的 LinqPad 程序来举例说明该方法的工作原理:
async void Main()
{
List<Post> postList = Enumerable.Range(1, 12).Select(id => new Post {Id = id}).ToList();
Console.WriteLine("Start Deletion");
await DeleteGivenPosts(postList);
Console.WriteLine("Finished Deletion");
}
public static MyRestClient wpRestClient = new MyRestClient();
// Define other methods and classes here
public async Task DeleteGivenPosts(List<Post> posts)
{
await Task.WhenAll(
posts.Select(async post =>
{
bool res = await wpRestClient.Delete(post.Id);
string message = res ? $"Post {post.Id} is deleted" : $"Post {post.Id} survived!";
Console.WriteLine(message);
}));
}
public static Random rand = new Random(DateTime.Now.Millisecond);
public class MyRestClient
{
public async Task<bool> Delete(int i)
{
return await Task<bool>.Run(() => { Thread.Sleep(400); return rand.Next(1,4) == 1;});
}
}
public class Post
{
public int Id { get; set; }
}
输出:
Start Deletion
Post 1 is deleted
Post 3 survived!
Post 5 survived!
Post 6 survived!
Post 2 survived!
Post 4 survived!
Post 8 survived!
Post 7 survived!
Post 9 survived!
Post 11 survived!
Post 10 is deleted
Post 12 is deleted
Finished Deletion
你也可以用你自己的方法包装它,像这样:
IEnumerable<Task<DeletionResult>> postDeletionTasks = posts.Select(post => DeletePost(post.Id));
您的方法和结果 class 可能类似于:
private async Task<DeletionResult> DeletePost(int postId)
{
bool result = await wpRestClient.Delete(postId);
return new DeletionResult(result, postId);
}
和
public class DeletionResult
{
public DeletionResult(bool result, int postId)
{
Result = result;
PostId = postId;
}
public bool Result { get; }
public int PostId { get; }
}
这样你就会得到一个任务列表,结果包含它所影响的 PostId
。