2010-12-10 9 views
5

.NETで非静的なスレッドメソッドを作成する方法はありますか? コードを表示してください。.NET - 非静的なスレッドメソッドを作成する方法はありますか?

次のコードは動作しない。

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

は、このエラーが発生します - >「フィールドの初期化は、非静的フィールド、メソッド、またはプロパティを参照することはできません」。 メソッドdo staticを変更した場合は動作します。しかし、私はしたくない。

+0

私のコードをしてください示しています。 – Seva

+1

drawFloorAround()のオブジェクトへの参照が必要です。 – phillip

+2

@philip:いいえ、どちらも動作しません。オブジェクトが「これ」であると思われる可能性が高い場合、同じエラーが発生します。 *フィールドイニシャライザで "this"を参照することはできません。* –

答えて

2

編集:サンプルコードの問題は、それがフィールドイニシャライザであることです。このコードを明示的なコンストラクタに移してください:

任意のメソッドは、ログ広告としてThreadStartとして動作し、argsを取らずにvoidを返します。これはクロージャを可能にするようIMO最も簡単なオプションは、ラムダまたは匿名メソッドです:

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

しかし、voidを返すと何の引数をとらないインスタンスメソッドのために:次に

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

var thread = new Thread(ts); 
+0

これは機能しません。私は質問 – Seva

+0

@Alanで詳細を与えるだろう - 2番目の例では、ちょうどあなたのメソッド名でのsomeMethodを置き換える:drawFloorAround。左側にオブジェクトを含めるものはありません(これは "this"かもしれません)。 –

+0

@Alan - 私は今見ます。答えを更新しています... –

5

を意味する場合は、非スタティックメソッド(つまりインスタンスメソッド)を使用してスレッドを開始することができます。しかし、インスタンスメソッドを直接呼び出す場合と同じ規則が適用されます。インスタンスがある場合にのみ実行できます。たとえば、あなたがfooという変数にインスタンスを持っている場合は、あなたがこれを書くことができます。

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

あなたはすでにあなたが使用できるインスタンスを持っていない場合は、あなたが最初のものを作成する必要があります。

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

インスタンスを作成しない場合は、おそらくメソッドが静的である必要があります。あなたはそれを設定するための何のインスタンスを持っていないので、

+0

はい...正確に...私はあなたに2票をあげてもいいと思います。 – phillip

+0

これは私のために働いた。新しいFoo()。DrawFloorAround .. ありがとうございました。メソッドは静的でなければなりません。しかし、メソッド内で私はキャンバスを呼び出しているので、静的なものに問題があります。 – Seva

4

はい

public class DoSomthing 
    { 

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

     public void DoInBackground() 
     { 
      // .... 
     } 

    } 
0

初期化子は、コンストラクタの前に実行します。あなたのコンストラクタの値を設定し、あなたは大丈夫です。

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

...「フィールド初期化子が非静的フィールド、メソッド、またはプロパティを参照することはできません」このエラーが発生します。

エラーメッセージをより注意深くお読みください。何が間違っているかを正確に伝えています。 フィールド初期化子は、非staticメソッドを参照できません。これは、コンパイラがこのバグからあなたを守るためです。

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

「新しいC(123)」を実行します。バーは何に設定されていますか?これが法的コードであれば、124ではなく1に設定されます。なぜですか?最初のfooが0に初期化され、GetBar()が呼び出されると、コンストラクタ本体はthis.fooを123に設定します。

このバグを回避するには、フィールドの初期化子でインスタンスメソッドまたはフィールドを参照することはできません。

さて、あなたは合理的にあなたのコードで、あなたがいない使用インスタンスメソッド、あなただけ参照にそれを行うことを指摘するかもしれません。あなたは実際にはと呼ぶことはありません。これは実際には安全です。しかし、C#のルールは単純で控えめに設計されています。我々はこのケースが安全であることを証明できるにもかかわらず、我々は保守的な、シンプルなパスを取り、フィールド初期化子内のインスタンスへいかなる参照が違法であると言います。

私は静的にメソッドを変更すると、それが動作します。

正しい。その場合、このメソッドは、まだセットアップされていないインスタンス状態に依存しません。

しかし、私はしたくありません。

[OK]を選択した場合、唯一の選択肢は フィールドイニシャライザの使用を中止することです。コンストラクタに初期化を入れます。初期化によって誤って初期化されていない状態が使用されないようにする責任があります。

0

それは、誰もが、ルールはVB.netとC#の間で変化していることに注意することがvb.netからのC#への移行のために重要です。 vb.net(IMHO better)のルールの下で、初期化子はmybase.newの呼び出しと次のコンストラクタの文の間で実行されます。フィールド初期化子が現在のオブジェクトのフィールドとプロパティを参照することは許されます。不注意に実行すると問題が発生する可能性がありますが、変数の初期化(場合によってはクリーンアップ)を宣言と同じ場所でソースコード内で処理できます。 C#に移行する人は、この初期化処理の違いを認識する必要があります。 vb.netでは、イニシャライザで作成されたiDisposableを適切に処分することは可能ですが、C#ではthreadstaticstatic変数を使用する厳しいkludgeを使用することはできません。

関連する問題