У вас есть данные, которые вы хотите сгруппировать по определенному значению, а затем неоднократно запускали в своем собственном цикле. Я приведу пример для одного из способов сделать , который, надеюсь, вы сможете опереться на то, что вам нужно для ответа.
Примечание. Этот пример может быть бесполезен в зависимости от того, как данные макетируются. Если вы зададите правильную структуру данных в своем вопросе, я обновлю ответ, чтобы он соответствовал.
У вас есть данные.
public struct Data
{
public Data(int value) => Value = value;
public int Value { get; }
public string Text => $"{nameof(Data)}: {Value}";
}
Требуется сгруппировать данные по определенному значению.
(ПРИМЕЧАНИЕ. Этот пример может быть нелогичным, поскольку он группирует данные по Value
, который уже уникален. Это добавляется только для примера:)
Есть много способов сделать это, но я буду использовать Linq
, Distinct
и IEqualityComparer<T>
для этого примера, который сравнивает Data.Value
.
public class DataDistinction : IEqualityComparer<Data>
{
public bool Equals(Data x, Data y) => x.Value == y.Value;
public int GetHashCode(Data obj) => obj.Value.GetHashCode();
}
Макет данных
Для этого примера я приведу некоторые данные.
var dataItems = new List<Data>();
for (var i = 0; i < 10; i++)
{
dataItems.Add(new Data(i));
}
Обработка данных
В этом примере я буду использовать IEqualityComparer<T>
, чтобы получить каждый Data
уникально по Value
и начать обработку.
private static void ProcessData(List<Data> dataItems)
{
var groupedDataItems = dataItems.Distinct(new DataDistinction());
foreach (var data in groupedDataItems)
{
LoopData(data); //We start unique loops here.
}
}
Цикл уникальных данных
Для этого примера я решил запустить новый Task
, используя Task.Factory
. Это может быть один раз, если это имеет смысл, но обычно вам это не нужно.
В этом примере я передаю Action<object>
, где объект представляет состояние или параметр, данный Task
.
Я также анализирую state
, который вы увидите, и запускаете цикл while
. Цикл while
контролирует CancellationTokenSource
для отмены. Для удобства я объявил CancellationTokenSource
в приложении статически; который вы увидите в полном консольном приложении внизу.
private static void LoopData(Data data)
{
Task.Factory.StartNew((state) =>
{
var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)
{
Console.WriteLine($"Value: {taskData.Value}\tText: {taskData.Text}");
Task.Delay(100).Wait();
}
},
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
}
Теперь я поместил все это в одно консольное приложение, которое вы можете копировать, вставлять и исследовать.
Это возьмет ваши данные, разбьет их и запустит все это на все время Task
до тех пор, пока программа не будет завершена.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Question_Answer_Console_App
{
class Program
{
private static readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
static void Main(string[] args)
{
var dataItems = new List<Data>();
for (var i = 0; i < 10; i++)
{
dataItems.Add(new Data(i));
}
ProcessData(dataItems);
Console.ReadKey();
cancellationTokenSource.Cancel();
Console.WriteLine("CANCELLING...");
Console.ReadKey();
}
private static void ProcessData(List<Data> dataItems)
{
var groupedDataItems = dataItems.Distinct(new DataDistinction());
foreach (var data in groupedDataItems)
{
LoopData(data);
}
}
private static void LoopData(Data data)
{
Task.Factory.StartNew((state) =>
{
var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)
{
Console.WriteLine($"Value: {taskData.Value}\tText: {taskData.Text}");
Task.Delay(100).Wait();
}
},
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
}
~Program() => cancellationTokenSource?.Dispose();
}
public struct Data
{
public Data(int value) => Value = value;
public int Value { get; }
public string Text => $"{nameof(Data)}: {Value}";
}
public class DataDistinction : IEqualityComparer<Data>
{
public bool Equals(Data x, Data y) => x.Value == y.Value;
public int GetHashCode(Data obj) => obj.Value.GetHashCode();
}
}
//OUTPUT UNTIL CANCELLED
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 5 Text: Data: 5
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 4 Text: Data: 4
//Value: 0 Text: Data: 0
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 6 Text: Data: 6
//Value: 5 Text: Data: 5
//Value: 3 Text: Data: 3
//Value: 8 Text: Data: 8
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 2 Text: Data: 2
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 8 Text: Data: 8
//Value: 5 Text: Data: 5
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 9 Text: Data: 9
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 4 Text: Data: 4
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 4 Text: Data: 4
//Value: 9 Text: Data: 9
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 5 Text: Data: 5
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 5 Text: Data: 5
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 1 Text: Data: 1
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 1 Text: Data: 1
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
// CANCELLING...
В комментариях вы спрашивали, как писать на консоль, когда Task
завершено. Вы можете await
Task
в этом примере, и когда Task
будет завершен, вы можете напечатать это Data
для показа. async void
не рекомендуется по уважительной причине, но это один раз, когда он используется правильно.
Вот обновленный LoopData
с подписью async await
.
private static async void LoopData(Data data)
{
await Task.Factory.StartNew((state) =>
{
var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)
{
Console.WriteLine($"Value: {taskData.Value}\tText: {taskData.Text}");
Task.Delay(100).Wait();
}
},
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
Console.WriteLine($"Task Complete: {data.Value} : {data.Text}");
}
//OUTPUT
//Value: 0 Text: Data: 0
//Value: 1 Text: Data: 1
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 1 Text: Data: 1
//Value: 6 Text: Data: 6
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 6 Text: Data: 6
//Value: 9 Text: Data: 9
// CANCELLING...
//Task Complete: 0 : Data: 0
//Task Complete: 2 : Data: 2
//Task Complete: 3 : Data: 3
//Task Complete: 1 : Data: 1
//Task Complete: 5 : Data: 5
//Task Complete: 4 : Data: 4
//Task Complete: 8 : Data: 8
//Task Complete: 6 : Data: 6
//Task Complete: 7 : Data: 7
//Task Complete: 9 : Data: 9..