Come si avvia una discussione con parametri in C #?
Come si avvia una discussione con parametri in C #?
Risposte:
Sì:
Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
void MyParamObject(object myUrl){ //do stuff }
dovrebbe avere il tipo di parametroobject
ParameterizedThreadStart
e chiaramente dal testo della domanda, probabilmente non è così.
Uno dei 2 sovraccarichi del costruttore di thread accetta un delegato ParameterizedThreadStart che consente di passare un singolo parametro al metodo start. Sfortunatamente però consente solo un singolo parametro e lo fa in modo non sicuro perché lo passa come oggetto. Trovo che sia molto più facile usare un'espressione lambda per catturare i parametri rilevanti e passarli in modo fortemente tipizzato.
Prova quanto segue
public Thread StartTheThread(SomeType param1, SomeOtherType param2) {
var t = new Thread(() => RealStart(param1, param2));
t.Start();
return t;
}
private static void RealStart(SomeType param1, SomeOtherType param2) {
...
}
Dim thr As New Thread(Sub() DoStuff(settings))
Puoi usare le espressioni lambda
private void MyMethod(string param1,int param2)
{
//do stuff
}
Thread myNewThread = new Thread(() => MyMethod("param1",5));
myNewThread.Start();
questa è finora la migliore risposta che ho trovato, è facile e veloce.
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
Il tipo di parametro deve essere un oggetto.
MODIFICARE:
Sebbene questa risposta non sia errata, sconsiglio questo approccio. L'uso di un'espressione lambda è molto più facile da leggere e non richiede il cast di tipo. Vedi qui: https://stackoverflow.com/a/1195915/52551
Parameter
?
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(new ParameterizedThreadStart(ThreadMethod));
t.Start("My Parameter");
}
static void ThreadMethod(object parameter)
{
// parameter equals to "My Parameter"
}
}
Modo semplice usando lambda in questo modo ..
Thread t = new Thread(() => DoSomething("param1", "param2"));
t.Start();
O potresti anche delegate
usare ThreadStart
così ...
ThreadStart ts = delegate
{
bool moreWork = DoWork("param1", "param2", "param3");
if (moreWork)
{
DoMoreWork("param4", "param5");
}
};
new Thread(ts).Start();
O usando VS 2019 .NET 4.5+ anche più pulito in questo modo ..
private void DoSomething(int param1, string param2)
{
//DO SOMETHING..
void ts()
{
if (param1 > 0) DoSomethingElse(param2, "param3");
}
new Thread(ts).Start();
//DO SOMETHING..
}
Come già menzionato in varie risposte qui, la Thread
classe attualmente (4.7.2) fornisce diversi costruttori e un Start
metodo con sovraccarichi.
Questi costruttori rilevanti per questa domanda sono:
public Thread(ThreadStart start);
e
public Thread(ParameterizedThreadStart start);
che può assumere un ThreadStart
delegato o un ParameterizedThreadStart
delegato.
I delegati corrispondenti si presentano così:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
Come si può vedere, il costruttore corretto da utilizzare sembra essere quello che prende un ParameterizedThreadStart
delegato in modo che un thread conforme alla firma specificata del delegato possa essere avviato dal thread.
Un semplice esempio per istanziare la Thread
classe sarebbe
Thread thread = new Thread(new ParameterizedThreadStart(Work));
o solo
Thread thread = new Thread(Work);
La firma del metodo corrispondente (chiamato Work
in questo esempio) è simile alla seguente:
private void Work(object data)
{
...
}
Ciò che resta è iniziare il thread. Questo viene fatto usando uno dei due
public void Start();
o
public void Start(object parameter);
Mentre Start()
avvia il thread e passa null
come dati al metodo, Start(...)
può essere utilizzato per passare qualsiasi cosa al Work
metodo del thread.
Esiste tuttavia un grosso problema con questo approccio: tutto ciò che viene passato nel Work
metodo viene inserito in un oggetto. Ciò significa che all'interno del Work
metodo deve essere nuovamente eseguito il cast nel tipo originale come nell'esempio seguente:
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}");
}
Il casting è qualcosa che di solito non vuoi fare.
Cosa succede se qualcuno passa qualcos'altro che non è una stringa? Dal momento che questo non sembra possibile all'inizio (poiché è il mio metodo, so cosa faccio o Il metodo è privato, come dovrebbe mai qualcuno essere in grado di passargli qualcosa? ), Potresti finire con quel caso per vari motivi . Poiché alcuni casi potrebbero non essere un problema, altri lo sono. In questi casi probabilmente finirai con una InvalidCastException
cosa che probabilmente non noterai perché termina semplicemente il thread.
Come soluzione ti aspetteresti di ottenere un ParameterizedThreadStart
delegato generico come ParameterizedThreadStart<T>
dove T
sarebbe il tipo di dati che vuoi passare al Work
metodo. Purtroppo qualcosa del genere non esiste (ancora?).
Esiste tuttavia una soluzione suggerita a questo problema. Implica la creazione di una classe che contenga sia i dati da passare al thread sia il metodo che rappresenta il metodo worker in questo modo:
public class ThreadWithState
{
private string message;
public ThreadWithState(string message)
{
this.message = message;
}
public void Work()
{
Console.WriteLine($"I, the thread write: {this.message}");
}
}
Con questo approccio inizieresti il thread in questo modo:
ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);
thread.Start();
Quindi in questo modo eviti semplicemente di lanciarti e hai un modo semplice di fornire dati a un thread ;-)
private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
message.Length
non è possibile e così via)
if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }
. Ad ogni modo, invece di utilizzare il metodo di threading ho trovato un po 'più comodo da usare Tasks<T>
, come per esempio tasks.Add(Task.Run(() => Calculate(par1, par2, par3)))
, vedere la mia risposta qui sotto ( stackoverflow.com/a/59777250/7586301 )
Ho riscontrato un problema con il parametro passato. Ho passato il numero intero da un ciclo for alla funzione e l'ho visualizzato, ma ha sempre dato risultati diversi. come (1,2,2,3) (1,2,3,3) (1,1,2,3) ecc. con delegato ParametrizedThreadStart .
questo semplice codice ha funzionato come un fascino
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
La ParameterizedThreadStart
prende un parametro. Puoi usarlo per inviare un parametro o una classe personalizzata contenente diverse proprietà.
Un altro metodo consiste nel mettere il metodo che si desidera avviare come membro di istanza in una classe insieme alle proprietà per i parametri che si desidera impostare. Crea un'istanza della classe, imposta le proprietà e avvia il thread specificando l'istanza e il metodo e il metodo può accedere alle proprietà.
È possibile utilizzare un delegato ParametrizedThreadStart :
string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);
Puoi utilizzare il metodo BackgroundWorker RunWorkerAsync e inserire il tuo valore.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApp6
{
class Program
{
static void Main(string[] args)
{
int x = 10;
Thread t1 =new Thread(new ParameterizedThreadStart(order1));
t1.IsBackground = true;//i can stope
t1.Start(x);
Thread t2=new Thread(order2);
t2.Priority = ThreadPriority.Highest;
t2.Start();
Console.ReadKey();
}//Main
static void order1(object args)
{
int x = (int)args;
for (int i = 0; i < x; i++)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(i.ToString() + " ");
}
}
static void order2()
{
for (int i = 100; i > 0; i--)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(i.ToString() + " ");
}
}`enter code here`
}
}
Propongo di utilizzare Task<T>
invece di Thread
; consente più parametri ed esegue davvero bene.
Ecco un esempio funzionante:
public static void Main()
{
List<Task> tasks = new List<Task>();
Console.WriteLine("Awaiting threads to finished...");
string par1 = "foo";
string par2 = "boo";
int par3 = 3;
for (int i = 0; i < 1000; i++)
{
tasks.Add(Task.Run(() => Calculate(par1, par2, par3)));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("All threads finished!");
}
static bool Calculate1(string par1, string par2, int par3)
{
lock(_locker)
{
//...
return true;
}
}
// if need to lock, use this:
private static Object _locker = new Object();"
static bool Calculate2(string par1, string par2, int par3)
{
lock(_locker)
{
//...
return true;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApp6
{
class Program
{
static void Main(string[] args)
{
int x = 10;
Thread t1 =new Thread(new ParameterizedThreadStart(order1));
t1.Start(x);
Thread t2=new Thread(order2);
t2.Priority = ThreadPriority.Highest;
t2.Start();
Console.ReadKey();
}//Main
static void order1(object args)
{
int x = (int)args;
for (int i = 0; i < x; i++)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(i.ToString() + " ");
}
}
static void order2()
{
for (int i = 100; i > 0; i--)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(i.ToString() + " ");
}
}
}
}