【问题标题】:How can I use a classes pre defined delegates in C#如何在 C# 中使用类预定义的委托
【发布时间】:2016-11-02 01:20:30
【问题描述】:

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

public delegate void PCMReaderCallback(float[] data);

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

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

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

【问题讨论】:

  • 你能把你的代码代替成吨的句子吗?
  • @LeiYang - 我已经采取了牛角并做了一些重新格式化的问题。我希望看到 OP 在使用回调的相关代码中添加。我尝试阅读文档,我可以看到它在哪里。
  • 这里是 Unity 文档页面中AudioClip.Create method overloads 的示例。这是否表明您需要做什么?
  • @AlexC 你主要关心什么:C# delegate/event 或 unity3d
  • 我在想象类似的东西。 public void MyMethod(parameter){我想要发生的事情} preExistingDelegate = MyMethod;

标签: c# unity3d delegates audioclip


【解决方案1】:

你有一个委托声明为:

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 为例。 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,则必须在主Thread 中调用回调。只是试图让这个例子保持简单。

【讨论】:

  • 谢谢你们!!!这一切真的很有帮助!我给大家投票!!!!
  • 不客气。你不能放弃投票,因为你没有足够的声誉这样做。您唯一能做的就是接受您认为对您最有帮助的答案之一。 Here 是怎么做的。
【解决方案2】:

委托是由您(或其他人)定义的一种方法描述类型。如果您熟悉 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;

然后在稍后的 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
}

【讨论】:

  • 谢谢大家,我这一切真的很有帮助!我给大家投票 Best Of The Best Alex
猜你喜欢
  • 2010-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-15
  • 2019-10-07
  • 2016-02-21
  • 1970-01-01
相关资源
最近更新 更多