1

我对编程相当陌生,目前正在尝试学习如何在 C# 中使用委托。我已经阅读了 MSDN 上的 C# delegates 编程指南,并查看了 Stack Overflow 上的一些其他示例。我想我得到了整体概念,但对如何使用已经在类中定义的委托感到困惑。例如,在 UnityAudioClip类中,PCMReaderCallback每次音频剪辑读取信息时都会调用一个委托。它采用的参数只是一个float值数组。

public delegate void PCMReaderCallback(float[] data);

我猜这意味着我可以使用这个委托来包装任何使用浮点数组作为参数的方法。在我经历过的教程中,他们解释了如何创建一个委托来包装您在定义委托时选择的方法,这对我没有帮助,因为PCMReaderCalledback 已经在AudioClip类中定义了。

我的问题是如何使用已经定义的委托来调用我选择的方法?

也许这是不可能的,或者我首先对代表的目的感到困惑。

4

2 回答 2

2

您有一个声明为:

public delegate void PCMReaderCallback(float[] data);

然后你有一个AudioClip.Create使用这个委托作为参数的 Unity 函数。这是这里唯一要理解的事情。

这是它的样子:

public static AudioClip Create(string name, int lengthSamples, int channels, int frequency, bool stream, PCMReaderCallback pcmreadercallback);

如您所见,它以PCMReaderCallback上面委托的名称作为参数。

现在,为了使用它,您首先需要创建一个与委托参数匹配的函数。请记住,我们的委托float[]作为参数并且是void返回类型。你给这个函数起什么名字并不重要。它应该如下所示:

void OnAudioRead(float[] data)
{

}

最后,要使用该功能:

AudioClip newAudioClip = AudioClip.Create("Pigeon", samplerate * 2, 1, samplerate, true, OnAudioRead);
AudioSource attachedSource = GetComponent<AudioSource>();
attachedSource.clip = newAudioClip;
attachedSource.Play();

如您所见,我们将OnAudioRead函数传递给参数,该参数将在每次读取数据时PCMReaderCallback pcmreadercallback调用我们的函数。这是由 Unity 自动调用的。OnAudioReadAudioClip

我的问题是如何使用已经定义的委托来调用我选择的方法?

让我们PCMReaderCallback作为一个例子。PCMReaderCallback在名为 的类中声明AudioClip。要使用它,您必须使用全名AudioClip.PCMReaderCallback

创建一个AudioClip.PCMReaderCallback作为参数的函数,进行一些数据处理,然后Invoke在处理完成时调用传入的函数:

void makeAlecAudioFunction(AudioClip.PCMReaderCallback allecCallBack)
{
    //Generate some random dummy audio data
    float[] dummyData = new float[4000];
    for (int i = 0; i < dummyData.Length; i++)
    {
        dummyData[i] = Random.Range(0f, 1f);
    }

    //Call the function that was passed in then pass it in the data we generated
    allecCallBack.Invoke(dummyData);
}

该功能的用法

创建一个将在makeAlecAudioFunction完成数据处理后调用的函数。

void OnAlecAudio(float[] data)
{
    for (int i = 0; i < data.Length; i++)
    {
        Debug.Log("Alec Audio Data: " + data[i]);
    }
}

现在,要调用makeAlecAudioFunction函数,调用它并传入OnAlecAudio函数。请记住,它们的参数必须匹配!:

makeAlecAudioFunction(OnAlecAudio);

最后,我认为回调函数背后的主要原因是做某事而不让程序的其余部分等待,然后在该操作完成时执行回调。因此,您makeAlecAudioFunction应该是一个协程函数,或者应该在另一个函数中调用Thread(在 Unity 中很复杂)。如果使用Thread,回调必须在 main 中调用Thread。只是试图保持这个例子简单。

于 2016-11-02T04:09:05.730 回答
1

委托是由您(或其他人)定义的一种方法描述类型。如果您熟悉 Action 和 Func 类型。它们是定义作为参数传递的预定义方法类型的委托。

例如,您的 typePCMReaderCallback(float[] data)可以在如下方法中使用:

public void ProcessData(PCMReaderCallback callback)
{
   List<float> data = new List<float>();
   // generate data here, or load it, etc
   // Then pass the data to the callback.
   callback(data.ToArray());
} 

因此,现在 ProcessData 可以采用具有该签名的各种方法。例如,

public void LogData(float[] data)
{
   // write the data to a log file
}

还有另一种方法

public void PrintData(float[] data)
{
   foreach(var d in data)
      Console.WriteLine(d.ToString());
}

你会调用 ProcessData 像......

ProcessData(LogData); // or...
ProcessData(PrintData);

委托也用于创建事件,然后可以订阅。看看事件和代表。但一个事件可能是,

public event PCMReaderCallback DataRead;

然后在稍后的 read 方法中,我们让世界知道数据已被读取,并且订阅了事件 DataRead 的任何人都可以使用它做一些事情。喜欢...

// read data here
// Then pass to event, first check to see if we have any subscribers.
if (DataRead != null)
{
   // Then prevent race conditions (subscribes and unsubscribes while processing events)
   var Event = DataRead;
   Event(data); // Then call the event here
}
于 2016-11-02T04:18:52.967 回答