C#でThread.ThreadStart()
メソッドにパラメータを渡す方法は?
「ダウンロード」という方法があるとします。
public void download(string filename)
{
// download code
}
これでメインメソッドにスレッドを1つ作成しました。
Thread thread = new Thread(new ThreadStart(download(filename));
エラーメソッドタイプが必要です。
どのように私はパラメータを持つターゲットメソッドでThreadStart
にパラメータを渡すことができますか?
最も簡単なのは
string filename = ...
Thread thread = new Thread(() => download(filename));
thread.Start();
(ParameterizedThreadStart
よりも)この利点は、複数のパラメータを渡すことができ、常にobject
からキャストする必要なしにコンパイル時のチェックができることです。
この例を見てください。
public void RunWorker()
{
Thread newThread = new Thread(WorkerMethod);
newThread.Start(new Parameter());
}
public void WorkerMethod(object parameterObj)
{
var parameter = (Parameter)parameterObj;
// do your job!
}
あなたは最初にworkerメソッドにデリゲートを渡すことによってスレッドを作成していて、それからパラメータとしてあなたのオブジェクトを受け取るThread.Startメソッドでそれを開始します。
だからあなたの場合あなたはこのようにそれを使うべきです:
Thread thread = new Thread(download);
thread.Start(filename);
しかし、あなたの 'download'メソッドは、パラメータとして文字列ではなくオブジェクトを受け取る必要があります。メソッド本体の中で文字列にキャストすることができます。
パラメータを取るスレッドメソッドには ParameterizedThreadStart
デリゲートを使用します。 (あるいは実際にはまったくなし。そしてThread
コンストラクターに推論させてください。)
使用例
var thread = new Thread(new ParameterizedThreadStart(download));
//var thread = new Thread(download); // equivalent
thread.Start(filename)
delegate
のようにすることもできます...
ThreadStart ts = delegate
{
bool moreWork = DoWork("param1", "param2", "param3");
if (moreWork)
{
DoMoreWork("param1", "param2");
}
};
new Thread(ts).Start();
スレッド関数(ダウンロード)と必要なパラメータ(ファイル名)をクラスにカプセル化し、ThreadStartデリゲートを使ってスレッド関数を実行できます。
public class Download
{
string _filename;
Download(string filename)
{
_filename = filename;
}
public void download(string filename)
{
//download code
}
}
Download = new Download(filename);
Thread thread = new Thread(new ThreadStart(Download.download);
追加で
Thread thread = new Thread(delegate() { download(i); });
thread.Start();
これはどうですか:(または、このように使用しても大丈夫ですか?)
var test = "Hello";
new Thread(new ThreadStart(() =>
{
try
{
//Staff to do
Console.WriteLine(test);
}
catch (Exception ex)
{
throw;
}
})).Start();
あなたの質問によると...
C#でThread.ThreadStart()メソッドにパラメータを渡す方法?
...そして、あなたが遭遇したエラー、あなたはからあなたのコードを修正しなければならないでしょう
Thread thread = new Thread(new ThreadStart(download(filename));
に
Thread thread = new Thread(new ThreadStart(download));
thread.Start(filename);
しかし、この質問は最初は思われるのでもっと複雑です。
Thread
クラス(4.7.2)では、いくつかの コンストラクタ と が提供されています。オーバーロードのある/ Start
method。
この質問に関連するコンストラクタは次のとおりです。
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
メソッドに anything を渡すために使用できます。
ただし、このアプローチには大きな問題が1つあります。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<T>
のような一般的なParameterizedThreadStart
デリゲートを取得することを期待します。ここで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();
だからこのようにあなたは単に回避することを避けそしてスレッドにデータを提供するタイプセーフな方法を持っています;-)