Відповідно до вашого запитання ...
Як передати параметри методу Thread.ThreadStart () у C #?
... і помилку, з якою ви зіткнулися, вам доведеться виправити свій код
Thread thread = new Thread(new ThreadStart(download(filename));
до
Thread thread = new Thread(new ThreadStart(download));
thread.Start(filename);
Однак питання складніше, як здається спочатку.
В Thread
даний час клас (4.7.2) містить декілька конструкторів та Start
метод із перевантаженнями.
Ці відповідні конструктори для цього питання:
public Thread(ThreadStart start);
і
public Thread(ParameterizedThreadStart start);
які або приймають ThreadStart
делегата, або ParameterizedThreadStart
делегата.
Відповідні делегати виглядають так:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
Отже, як видно, правильний конструктор для використання, здається, є тим, хто приймає ParameterizedThreadStart
делегата, так що якийсь метод, відповідний вказаній підписі делегата, може бути запущений потоком.
Простий приклад для інстанціювання Thread
класу
Thread thread = new Thread(new ParameterizedThreadStart(Work));
або просто
Thread thread = new Thread(Work);
Підпис відповідного методу (називається Work
в цьому прикладі) виглядає так:
private void Work(object data)
{
...
}
Залишилося запустити нитку. Це робиться за допомогою будь-якого
public void Start();
або
public void Start(object parameter);
Хоча Start()
запускається потік і передається null
як дані методу, Start(...)
може використовуватися для передачі чого-небудь в Work
метод потоку.
Однак у цьому підході є одна велика проблема: все, що передається Work
методу, передається об'єкту. Це означає, що в рамках Work
методу його потрібно передати оригінальному типу знову, як у наступному прикладі:
public static void Main(string[] args)
{
Thread thread = new Thread(Work);
thread.Start("I've got some text");
Console.ReadLine();
}
private static void Work(object data)
{
string message = (string)data; // Wow, this is ugly
Console.WriteLine($"I, the thread write: {message}");
}
Кастинг - це те, чого ти зазвичай не хочеш робити.
Що робити, якщо хтось передає щось інше, що не є рядком? Оскільки це здається неможливим спочатку (оскільки це мій метод, я знаю, що я роблю, або метод є приватним, як хто-небудь коли-небудь зможе передати йому що-небудь? ), Можливо, у вас може виникнути саме такий випадок з різних причин . Оскільки деякі випадки можуть не бути проблемою, інші є. У таких випадках у вас, ймовірно, вийде кінецьInvalidCastException
чого ви, ймовірно, не помітите, оскільки воно просто завершує нитку.
Як рішення, ви б очікували отримати загальний ParameterizedThreadStart
делегат, наприклад, ParameterizedThreadStart<T>
де T
буде тип даних, який ви хочете передати в Work
метод. На жаль, щось подібне не існує (поки що?).
Однак існує вирішення цього питання. Він включає створення класу, який містить обидва, дані, що передаються в потік, а також метод, який представляє такий собі робочий метод:
public class ThreadWithState
{
private string message;
public ThreadWithState(string message)
{
this.message = message;
}
public void Work()
{
Console.WriteLine($"I, the thread write: {this.message}");
}
}
При такому підході ви б почали нитку так:
ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);
thread.Start();
Тож таким чином ви просто уникаєте закидання та маєте безпечний спосіб надання даних у потік ;-)