.NET – Est-il possible de créer une méthode de thread non statique?

Est-il possible de créer une méthode de thread non statique sur .NET? Montrez-moi le code s’il vous plaît.

Le code suivant ne fonctionne pas:

 ThreadStart ts = delegate {drawFloorAround ();  };
 public void drawFloorAround ()
 {
             ...
 }

Donne cette erreur -> “Un initialiseur de champ ne peut pas référencer le champ, la méthode ou la propriété non statique”. Si je change la méthode do static, cela fonctionne. Mais je ne veux pas.

… donne cette erreur “Un initialiseur de champ ne peut pas référencer le champ, la méthode ou la propriété non statique”.

Lisez le message d’erreur plus attentivement. Il vous dit précisément ce qui ne va pas. Un initialiseur de champ ne peut pas référencer une méthode non statique . C’est parce que le compilateur essaie de vous protéger de ce bogue:

class C { int foo; int bar = GetBar(); public C(int newFoo) { this.foo = newFoo; } private int GetBar() { return this.foo + 1; } } 

Vous faites “new C (123)”. Quelle est la barre définie à? S’il s’agissait d’un code légal, il serait mis à 1 et non 124. Pourquoi? Parce que le premier foo est initialisé à zéro, puis GetBar () est appelé, puis le corps du constructeur définit this.foo sur 123.

Pour éviter ce bogue, il est simplement illégal de faire référence à une méthode d’instance ou à un champ dans un initialiseur de champ.

Maintenant, vous pouvez raisonnablement indiquer que dans votre code, vous n’utilisez pas la méthode d’instance, vous la faites simplement référencer . Vous ne l’ appelez jamais réellement. C’est en fait sûr. Cependant, les règles de C # sont conçues pour être simples et conservasortingces; Même si nous pouvons prouver que cette affaire est sûre, nous prenons le chemin conservateur et simple et disons que toute référence à l’instance dans un initialiseur de champ est illégale.

Si je change la méthode en statique, cela fonctionne.

Correct. Dans ce cas, la méthode ne dépend pas de l’état de l’instance qui n’a pas encore été configuré.

Mais je ne veux pas.

OK, votre seul autre choix est de cesser d’utiliser un initialiseur de champ . Mettez l’initialisation dans le constructeur; vous prenez alors la responsabilité de vous assurer que l’initialisation n’utilise pas accidentellement l’état non initialisé.

Si vous voulez dire s’il est possible de démarrer un thread avec une méthode non statique – c’est-à-dire une méthode d’instance -, alors c’est le cas. Mais les mêmes règles s’appliquent pour appeler directement une méthode d’instance – vous ne pouvez le faire que si vous avez une instance. Par exemple, si vous avez une instance dans une variable appelée foo vous pouvez écrire ceci:

 ThreadStart ts = delegate { foo.DrawFloorAround(); }; 

Si vous ne disposez pas déjà d’une instance que vous pouvez utiliser, vous devez d’abord en créer une:

 ThreadStart ts = delegate { new Foo().DrawFloorAround(); }; 

Si vous ne voulez pas créer d’instance, votre méthode devrait probablement être statique.

Oui

  public class DoSomthing { public void Do() { Thread t = new Thread(DoInBackground); t.Start(); } public void DoInBackground() { // .... } } 

Edit: le problème dans l’exemple de code est qu’il s’agit d’un initialiseur de champ. Déplacez ce code vers un constructeur explicite:

 ThreadStart ts; public TypeName() {//constructor ts = this.SomeMethod; } private void SomeMethod() {....} 

Toute méthode peut agir comme un ThreadStart en tant qu’annonce de journal, elle ne prend pas d’argument et retourne void. L’option la plus simple de l’OMI est une méthode lambda ou anon car elle permet les fermetures:

 ThreadStart ts = delegate { someObj.DoSomething(x, y, "z"); }; 

Mais pour une méthode d’instance qui retourne void et ne prend aucun argument:

 var obj = /* init obj */ ThreadStart ts = obj.SomeMethod; 

ensuite

 var thread = new Thread(ts); 

Les initialiseurs s’exécutent avant les constructeurs, vous n’avez donc aucune instance pour le définir. Définissez la valeur dans votre constructeur et vous devriez aller bien.

 class DoesNotWork { public Action ts = Frob; // doesn't work, cannot access non-static method void Frob() { } } class ThisIsFine { public Action ts; public ThisIsFine() { ts = Frob; } void Frob(); } 

Il est important pour toute personne passant de vb.net à C # de noter que les règles ont changé entre VB.net et C #. Selon les règles vb.net (IMHO better), les initialiseurs s’exécutent entre l’appel de mybase.new et l’instruction suivante du constructeur; Les initialiseurs de champs peuvent faire référence aux champs et aux propriétés de l’object en cours. Bien que cela puisse poser des problèmes si cela est fait sans précaution, cela permet de gérer l’initialisation des variables (et parfois le nettoyage) au même endroit dans le code source que la déclaration. Toute personne migrant en C # doit reconnaître cette différence dans la gestion des initialiseurs. Bien qu’il soit possible dans vb.net de disposer correctement d’un iDisposable créé dans un initialiseur, cela n’est pas possible en C # sans un kludge sévère utilisant une variable threadstatic.