如何使用C#中预先定义的类委托



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

public delegate void PCMReaderCallback(float[] data);

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

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

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

您有一个委托声明为:

public delegate void PCMReaderCallback(float[] data);

然后有一个Unity AudioClip.Create函数,它将此委托用作参数。这是这里唯一需要理解的东西。

这就是它的样子:

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参数,该参数将在每次AudioClip读取数据时调用OnAudioRead函数。这是Unity自动调用的。

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

让我们以PCMReaderCallback为例。CCD_ 15是在一个称为CCD_ 16的类中声明的。要使用它,必须使用全名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,则必须在主Thread中调用回调。只是想让这个例子保持简单。

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

例如,您的类型PCMReaderCallback(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;

然后在稍后的读取方法中,我们让世界知道数据已经被读取,任何订阅了事件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
}

相关内容

  • 没有找到相关文章

最新更新