web-dev-qa-db-ja.com

ThreadでThreadStartメソッドにパラメータを渡す方法は?

C#でThread.ThreadStart()メソッドにパラメータを渡す方法は?

「ダウンロード」という方法があるとします。

public void download(string filename)
{
    // download code
}

これでメインメソッドにスレッドを1つ作成しました。

Thread thread = new Thread(new ThreadStart(download(filename));

エラーメソッドタイプが必要です。

どのように私はパラメータを持つターゲットメソッドでThreadStartにパラメータを渡すことができますか?

270
Swapnil Gupta

最も簡単なのは

string filename = ...
Thread thread = new Thread(() => download(filename));
thread.Start();

ParameterizedThreadStartよりも)この利点は、複数のパラメータを渡すことができ、常にobjectからキャストする必要なしにコンパイル時のチェックができることです。

656
Marc Gravell

この例を見てください。

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'メソッドは、パラメータとして文字列ではなくオブジェクトを受け取る必要があります。メソッド本体の中で文字列にキャストすることができます。

33
ŁukaszW.pl

パラメータを取るスレッドメソッドには ParameterizedThreadStart デリゲートを使用します。 (あるいは実際にはまったくなし。そしてThreadコンストラクターに推論させてください。)

使用例

var thread = new Thread(new ParameterizedThreadStart(download));
//var thread = new Thread(download); // equivalent

thread.Start(filename)
22
Noldorin

delegateのようにすることもできます...

ThreadStart ts = delegate
{
      bool moreWork = DoWork("param1", "param2", "param3");
      if (moreWork) 
      {
          DoMoreWork("param1", "param2");
      }
};
new Thread(ts).Start();
4
Master Mick

スレッド関数(ダウンロード)と必要なパラメータ(ファイル名)をクラスにカプセル化し、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);
2
Jackypengyu

追加で

    Thread thread = new Thread(delegate() { download(i); });
    thread.Start();
2
Metin Atalay

これはどうですか:(または、このように使用しても大丈夫ですか?)

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デリゲートを取得することを期待します。ここでTWorkメソッドに渡したいデータのタイプです。残念ながら、このようなものは存在しません(まだ?)。

しかし、この問題には が推奨する解決策 があります。これには、スレッドに渡されるデータと、このようなワーカーメソッドを表すメソッドの両方を含むクラスを作成することが含まれます。

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();

だからこのようにあなたは単に回避することを避けそしてスレッドにデータを提供するタイプセーフな方法を持っています;-)

0
Markus Safar