C# 错误:非静态字段需要对象引用
本文关键字:对象引用 字段 静态 错误 | 更新日期: 2023-09-27 18:37:18
我有一个小的Windows表单程序,它使用console.beep从字符串播放音乐。我在一个新的线程"t"中设置了字符串播放位(它基本上是一个 for 循环,通过字符串 char 一个字符并播放适当的音符)。当您点击"播放"按钮时,线程启动,按钮变为"停止"按钮。如果您在播放音乐时点击此"停止"按钮,它将停止并且按钮将变回播放(通过调用"完成"方法。我的问题是,我希望在新线程中运行的循环在循环运行并且歌曲结束时也调用"完成"方法。但是如果我在循环之后放置 finish(),我会得到"非静态字段需要对象引用"错误。如果我将"finshed"方法更改为静态,那么更改按钮文本的位将不起作用......
这是按下按钮时的代码...
//This is the method for when the "start" button is clicked
public void button1_Click(object sender, EventArgs e)
{
if (music == null) { return; }
if (button1.Text == "Play")
{
// it makes a new thread which calls my "parse" method which
// interprets the music and then calls "playnote" to play it.
Thread t = new Thread(parse);
t.Start();
button1.Text = "Stop";
}
else
{
finished();
}
}
public void finished()
{
stop = true;
button1.Text = "Play";
}
有什么建议吗?
提前非常感谢!
编辑:谢谢大家!!我真的没有时间弄清楚后台工作人员 atm,所以我现在只有单独的开始和停止按钮!:p
我认为使用BackgroundWorker 线程可以更好地完成此操作。这样,您就可以在RunWorkerCompleted
事件中调用 finished()
方法。
parse() 方法是静态的吗?似乎您正在尝试从静态方法调用 done() 而不提供实例,这就是您收到"非静态字段需要对象引用"错误的原因。
做的是确保创建的线程可以访问创建它的对象(即"this",在您的"button1_Click()"方法的范围内)。为此,您可以调用 t.Start(this) 而不是 t.Start()。这样做,您将向线程传递能够调用"finish()"方法的对象。接下来,您需要确保"parse"方法采用 Object 类型的参数。这样做时,当您调用"t.Start(this)"时,方法"parse"将接收"this"作为参数。需要简单的强制转换才能转换为适当的类型。现在,当您希望在线程中停止歌曲时,只需在强制转换参数上调用"finish()"方法即可。因此,您的代码应如下所示:
公共无效解析(对象 O){ MyClass c = o as MyClass;将 MyClass 替换为您的类的名称
[...] // play music here
c.finished(); // call finished when you are done
}
public void button1_Click(Object sender, EventArgs e){ [...]
线程 t = 新线程(解析); t.开始(这个);而不是 t.Start()
[...]}
静态与成员方法
- 要么你有一个成员(非静态)方法,你调用它
obj.SomeMethod();
- 或者你有一个静态方法,你调用它
ClassName.SomeMethod();
除非它在定义类本身内部调用。然后可以简单地调用它
SomeMethod();
在这两种情况下。
线程
唯一允许与UI交互(例如与button1.Text
)交互的线程是UI线程本身。UI 线程是代码正常运行的主线程。
请参阅如何在 C# 中从另一个线程更新 GUI?,以便与另一个线程中的窗体进行交互。
你需要做的是在主线程上引发一个事件来调用你完成的方法。首先在窗体类中声明事件和委托。
public delegate void CallFinishedEventHandler();
public event CallFinishedEventHandler CallFinished;
然后创建一个事件处理程序,该处理程序将在引发事件时调用,并在 调用已完成的方法。
void Form1_CallFinished()
{
Finished();
}
然后在窗体构造函数中将事件处理程序连接到事件。
public Form1()
{
CallFinished += Form1_CallFinished;
}
最后,在音乐播放代码中,当您想要调用已完成的方法(在 UI 线程上)时,请调用您的事件,以便在 UI 线程上触发它。
this.Invoke(CallFinished);
这很简单,创建一个全局线程,然后在您想要的位置访问它。
Thread t;
public void button1_Click(object sender, EventArgs e)
{
if (music == null) { return; }
if (button1.Text == "Play")
{
// it makes a new thread which calls my "parse" method which
// interprets the music and then calls "playnote" to play it.
t = new Thread(parse);
t.Start();
button1.Text = "Stop";
}
else
{
finished();
}
}
public void finished()
{
stop = true;
button1.Text = "Play";
}
对于调用 finish,创建窗体类的实例,然后调用该方法。
Form1 frm1 = new Form1();
frm1.finished();