Как создать конкретное количество элементов в словаре? - PullRequest
0 голосов
/ 30 октября 2018

Я пытаюсь объявить Dictionary<Task> с определенным количеством предметов, я пробовал:

private Dictionary<Task, CancellationToken> bots = 
        new Dictionary<Task, CancellationToken>(new Task[9], new CancellationToken[9]);

это вернет следующую ошибку:

вы не можете конвертировать из 'System.Threading.Tasks.Task []' в 'System.Collections.Generic.IDictionary'

все работает, если я делаю это в List:

private List<Task> bots = new List<Task>(new Task[9]);

Ответы [ 3 ]

0 голосов
/ 30 октября 2018

Как показывает ошибка, вы пытаетесь сделать что-то, чего не существует.

Один из переопределенных конструкторов Dictionary принимает

public Dictionary(IDictionary<TKey, TValue> dictionary);
public Dictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer);

И ни один из указанных вами параметров не является правильным. Первый ввод, который вы дали, это Task [], а второй - CancellationToken []

.

Вы должны создать реализацию IDictionary, которая обычно представляет собой словарь, а затем передать его ему.

var example1Original = new Dictionary<Task, CancellationToken>();
example1Original.Add(new Task(DoWork), new CancellationToken());
example1Original.Add(new Task(DoWork), new CancellationToken());
// and more (This procedure can be shorten using a loop)

var example1Result = new Dictionary<Task, CancellationToken>(example1Original);

Как видите, мы успешно передали нашу переменную в конструктор Dictionary, это возможно потому, что Dictionary реализует IDictionary, как мы можем видеть здесь image">

Но последняя строка фактически избыточна, потому что да, мы можем ее пропустить, но нам это не нужно. Потому что наш заполненный пример exampleOriginal уже является словарем, к которому мы стремимся.

Таким образом, возникает вопрос, почему конструктор Dictionary имеет это в первую очередь. Это приводит нас к нашему первоначальному утверждению, что IDictionary может иметь несколько реализаций, которые можно передавать.

Вот несколько реализаций IDictionary image implementations">
(Изображение взято с mscorlib.dll с использованием ILSpy)

Итак, ваш вопрос на самом деле, как я могу заполнить свой словарь новыми экземплярами жетонов задач и отмены.

Это можно сделать с помощью:

  1. Предыдущий код выше. (И укоротить еще на петлю)
  2. Или используя более короткие языковые возможности.

Возможности, которые мы собираемся использовать

  • System.Linq.Enumerable.Range - генерирует последовательность целых чисел в указанном диапазоне.
  • System.Linq.Enumerable.Select - Проецирует каждый элемент последовательности в новую форму.
  • Сила интерфейсов - для того, чтобы мы могли использовать метод расширения ToDictionary.
  • System.Linq.Enumrable.ToDictionary () - Метод расширения, который принимает IEnumerable и генерирует словарь

Enumerable.ToDictionary - поскольку сам IDictionary реализует IEnumerable, мы можем затем использовать следующий метод расширения ToDictionary

Метод расширения из System.Linq Пространство имен

public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector);

Если мы будем использовать эти возможности, мы можем создать следующее для создания нашего словаря.

var kvpOfTaskCancellation = Enumerable.Range(0, 9) // Generates Enumerable integers sequence.
    .Select(i => new KeyValuePair<Task, CancellationToken>(new Task(DoWork), new CancellationToken())) // Iterating and projecting every elements inside the previous generated sequence.
    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); // Mapping each iteration from the previous line KeyValuePair objects to the Dictionary Key and Value.

Что также можно сократить до следующего

var kvpOfTaskCancellation2 = Enumerable.Range(0, 9)
    .ToDictionary(kvp => new Task(DoWork), kvp => new CancellationToken());

Это все работает, если вам нужен новый маркер Задачи и Отмена.

Но Если у вас уже есть заполненная коллекция Tasks и CancellationTokens, и вы хотите сгенерировать из них словарь, вы можете сделать следующее:

var tasks = new Task[3];
// I'm assuming the tasks already been populated
tasks.ToDictionary(kvp => kvp, kvp => new CancellationToken());

Но если у вас также есть массив CancellationToken, то вы можете использовать следующее:

var tasks = new Task[3];
var cancellationsTokens = new CancellationToken[9];
// I'm assuming tasks and cancellationToken array already been filled.
Enumerable.Range(0, tasks.Length)
    .Select(i => new KeyValuePair<Task, CancellationToken>(tasks[i], cancellationsTokens[i]))
    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
0 голосов
/ 30 октября 2018

Неинициализированный массив Task содержит только нулевые элементы, и вы не можете иметь значение null в качестве ключа элемента словаря, но в целом, если вы инициализировали массивы, вы можете иметь словари с этими массивами, используя Linq:

var dictionary = (from token in new CancellationToken[9]
                 from task in initializedTaskArray
                 select (task, token)
                 )
                 .ToDictionary(x => x.task, x => x.token);
0 голосов
/ 30 октября 2018

Вам нужно сделать что-то вроде следующего:

private Dictionary<Task, CancellationToken> bots = new Dictionary<Task, CancellationToken>() {
    { new Task(), new CancellationToken() },
    { new Task(), new CancellationToken() },
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...