Как передать метод с параметрами в 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 шт):
Если сигнатура вашего метода ничем не отличается от 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 классы.