Как передать метод с параметрами в Thread?

Как метод Fill запихнуть в новый поток? Как заставить это работать?

for (int i = 0; i < 5; i++)
                {
                    Thread myThread = new Thread(new ParameterizedThreadStart(Fill));
                    myThread.Start(a);
                    myThread.Name = "Поток " + i.ToString();
                }

     static void Fill(int[] a)
            {
                Random rand = new Random();
                for (int i = 0; i < a.Length; i++)
                    a[i] = rand.Next(-100, 100);
            }

Ответы (1 шт):

Автор решения: return

Если сигнатура вашего метода ничем не отличается от ThreadStart/ParameterizedThreadStart, то нужно просто передать делегат внутрь конструктора класса Thread:

var thread = new Thread(MyMethod);

Ситуация также проста, если нам нужно передать 1 аргумент, до типа, производного от object:

static void MyMethod(string @string) { ... }

В таком случае можно просто создать лямбду-обёртку1:

var thread = new Thread(arg => MyMethod(arg as string));
thread.Start("My String.");

А вот с передачей нескольких параметров не так всё просто. Например, у нас есть след. метод:

static MyOtherMethod(int a, string b, double c) { ... }

Можно просто пойти в лоб и следать что-то типо такого:

var thread = new Thread(() => MyOtherMethod(a, b, c));
thread.Start();

Это хороший метод, он полезен своей читаемостью, но при каждых новых значениях a, b или c создаётся новая лямбда, что не есть хорошо. Это можно использовать при редких/единичный созданиях нового потока, но не при переодических.

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

// всегда `class`, т.к. быстрее оборачивается в `object`
class MyThreadArgs
{
    // Можно использовать вместо полей св-ва:
    // public int A { get; init; }
    // Использование св-в *обязательно*, если класс публичный.
    public int A;
    public string B;
    public double C;
}
var thread = new Thread(arg => {
   var args = arg as MyThreadArgs;

   MyOtherMethod(args.A, args.B, args.C);
});
thread.Start(new MyThreadArgs { A = 13, B = "Other string.", C = 3.14 });

Этот метод быстр и обязателен в случае, если тип передаваемых аргументов публичный, но гораздо изящнее выглядит метод с анонимными типами и dynamic:

var thread = new Thread((dynamic args) => MyOtherMethod(args.A, args.B, args.C));
thread.Start(new { A = 13, B = "Other string.", C = 3.14 });

Но у вас может возникнуть логичный вопрос: как мы лямбду, принимающую dynamic представили как ParameterizedThreadStart, принимающий object? Всё просто: dynamic — это тот же object, только компилятор даёт нам возможность пользоваться этим синтаксическим сахаром (вместо сложного (int)args.GetType().GetProperty("A").GetValue(args) делать простое args.A).


Но, как и любого красивого кода, есть обратная сторона: он медленный. Случай с dynamic не стал исключением, т.к. необходимые поля/св-ва/методы находятся не статически (во время компиляции), а динамически (во время исполнения программы).


1 — в коде не используются nullable классы.

→ Ссылка