简体   繁体   English

如何在C#中使用预定义的类代理

[英]How can I use a classes pre defined delegates in C#

Im fairly new to programming and am currently attempting to learn how to use delegates in C#. 我是一个相当新的编程,我目前正在尝试学习如何在C#中使用委托。 I've read the C# delegates programming guide on MSDN and have looked at some other examples on Stack Overflow. 我已经在MSDN上阅读了C#delegates编程指南,并查看了Stack Overflow上的其他一些示例。 I think I get the overall concept, but am confused on how to use a delegate which is already defined in a class. 我认为我得到了整体概念,但我对如何使用已在类中定义的委托感到困惑。 For example in the Unity AudioClip class, there is a delegate called PCMReaderCallback which is called every time an audio clip reads information. 例如,在Unity AudioClip类中,有一个名为PCMReaderCallback的委托,每次音频剪辑读取信息时都会调用该委托。 The parameters that it takes are simply an array of float values. 它所采用的参数只是一个float值数组。

public delegate void PCMReaderCallback(float[] data);

I'm guessing that that means I can use this delegate to wrap any method that uses a float array as a parameter. 我猜这意味着我可以使用这个委托来包装任何使用float数组作为参数的方法。 On the tutorials I've been through they explain how to create a delegate that wraps up a method which you chose when defining the delegate, which doesn't help me since PCMReaderCalled back is already defined in the AudioClip class. 在我经历过的教程中,他们解释了如何创建一个包含你在定义委托时选择的方法的委托,这对我没有帮助,因为已经在AudioClip类中定义了PCMReaderCalled

My question is how would I use a delegate which has already been defined to call on a method of my choice? 我的问题是如何使用已经定义的委托来调用我选择的方法?

Perhaps this is not possible or perhaps I am confused about the purpose of delegates in the first place. 也许这是不可能的,或者我可能首先对代表们的目的感到困惑。

You have a delegate declared as: 您有一个委托声明为:

public delegate void PCMReaderCallback(float[] data);

Then you have a Unity AudioClip.Create function that uses this delegate as a parameter. 然后你有一个Unity AudioClip.Create函数,它使用这个委托作为参数。 This is the only thing to understand here. 这是唯一要理解的内容。

This is what it looks like: 这就是它的样子:

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

As, you can see, it takes PCMReaderCallback as parameter which is the name of the delegate above. 您可以看到,它需要PCMReaderCallback作为参数,这是上面PCMReaderCallback的名称。

Now, in order to use it, you first have a to create a function that matches the parameter of the delegate. 现在,为了使用它,首先要创建一个与委托参数匹配的函数。 Remember that our delegate takes float[] as a parameter and is a void return type. 请记住,我们的委托将float[]作为参数,并且是一个void返回类型。 It really doesn't matter what you name this function. 你命名这个函数真的没关系。 It should look like something below: 它应该如下所示:

void OnAudioRead(float[] data)
{

}

Finally, to use the function: 最后,要使用该功能:

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

As, you can see, we passed in our OnAudioRead function to the PCMReaderCallback pcmreadercallback parameter which will call our OnAudioRead function when each time AudioClip reads data. 您可以看到,我们将OnAudioRead函数传递给PCMReaderCallback pcmreadercallback参数,该参数将在每次AudioClip读取数据时调用我们的OnAudioRead函数。 This is automatically called by Unity. 这是Unity自动调用的。

My question is how would I use a delegate which has already been defined to call on a method of my choice? 我的问题是如何使用已经定义的委托来调用我选择的方法?

Let's use PCMReaderCallback as an example. 我们以PCMReaderCallback为例。 PCMReaderCallback is declared in a class called AudioClip . PCMReaderCallback在名为AudioClip的类中声明。 To use use it, you must use the full name AudioClip.PCMReaderCallback . 要使用它,您必须使用全名AudioClip.PCMReaderCallback

Create a function that takes AudioClip.PCMReaderCallback as parameter, do some data processing, then use Invoke to call that function that is passed in when processing is done: 创建一个函数,将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);
}

Usage of that function : 该功能的用法

Create a function that will be called when makeAlecAudioFunction has finished processing data. 创建一个在makeAlecAudioFunction完成处理数据时将调用的函数。

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

Now, to call the makeAlecAudioFunction function, call it and pass in the OnAlecAudio function. 现在,要调用makeAlecAudioFunction函数,请调用它并传入OnAlecAudio函数。 Remember that their parameter must match!: 请记住,他们的参数必须匹配!:

makeAlecAudioFunction(OnAlecAudio);

Finally, I think that the main reason behind callback functions is to do something without making the rest of the program wait, then perform a callback when that action is done. 最后,我认为回调函数背后的主要原因是在不使程序的其余部分等待的情况下执行某些操作,然后在该操作完成时执行回调。 Because of this, your makeAlecAudioFunction should be a coroutine function or should be called in another Thread (complicated in Unity). 因此,你的makeAlecAudioFunction应该是一个协程函数,或者应该在另一个Thread调用(在Unity中很复杂)。 If using Thread , the callback must be called in the main Thread . 如果使用Thread ,则必须在主Thread调用回调。 Just trying to keep this example simple. 试着保持这个例子简单。

A delegate is a type defined by you (or another), of a description of a method. 委托是您(或另一个)定义的方法描述类型。 If you're familiar with the types Action, and Func. 如果您熟悉Action和Func类型。 They are delegates defining pre-defined method types that are passed as arguments. 它们是定义作为参数传递的预定义方法类型的委托。

For instance, your type PCMReaderCallback(float[] data) , can be used in a method like so: 例如,您的类型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());
} 

So now the ProcessData can take various methods with that signature. 所以现在ProcessData可以采用该签名的各种方法。 For example, 例如,

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

And another method 另一种方法

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

And you'd call ProcessData like... 你会像ProcessData一样调用ProcessData

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

Also delegates are used to create events, that can be then subscribed to. 委托也用于创建事件,然后可以订阅。 Have a look at events and delegates. 看看活动和代表。 But an event could be, 但事件可能是,

public event PCMReaderCallback DataRead;

Then later in a read method, we let the world know that the data has been read and anyone that's subscribed to the event DataRead can do something with it. 然后在读取方法中,我们让世界知道数据已被读取,并且订阅事件DataRead的任何人都可以使用它做任何事情。 Like... 喜欢...

// 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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM