1

Im fairly new to programming and am currently attempting to learn how to use delegates in C#. I've read the C# delegates programming guide on MSDN and have looked at some other examples on 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. The parameters that it takes are simply an array of float values.

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. 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.

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.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
AlexC
  • 39
  • 4
  • Can you put you **code** instead of tons of sentences? – Lei Yang Nov 02 '16 at 01:46
  • @LeiYang - I've taken the bull by the horns and done some reformatting of the question. I would like to see the OP add in the relevant code for where the callback is used. I tried reading the documentation and I could see where it is. – Enigmativity Nov 02 '16 at 01:50
  • Here is the example from the Unity documentation page for the [`AudioClip.Create` method overloads](https://docs.unity3d.com/ScriptReference/AudioClip.Create.html). Does that show you what you need to do? – Enigmativity Nov 02 '16 at 01:58
  • @AlexC What is your main concern: **C# delegate/event or unity3d**? – Lei Yang Nov 02 '16 at 02:12
  • Im imagining something like. public void MyMethod(parameter){what i want to happen} preExistingDelegate = MyMethod; – AlexC Nov 02 '16 at 03:09
  • Im more interested in understanding delegates. The code i just wrote won't work but i'm thinking there should be some way to assign a delegate which you didn't create to a method which you do create. So that whenever that delegate gets called it also calls your method – AlexC Nov 02 '16 at 03:11
  • Of course if I create a delegate i can instantiate it and then set it equal to my method, but with a delegate from a class, like PCMReaderCallBack. I dont see how i could instantiate it so I dont see how i could encapsulate my method with it.\ – AlexC Nov 02 '16 at 03:15
  • For example using delegates in this way will work. public delegate void MyDelegate(string message); public static void MyMethod(string message) { System.Console.WriteLine(message); } myDelegate del = MyMethod – AlexC Nov 02 '16 at 03:20
  • That last bit is just from the MSDN tutorial https://msdn.microsoft.com/en-us/library/ms173172.aspx. Im just wondering if i could take it a step further and attach a method to delegates which i didn't create – AlexC Nov 02 '16 at 03:22
  • Thanks for baring with me ! – AlexC Nov 02 '16 at 03:24

2 Answers2

2

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. 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.

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. 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. This is automatically called by 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 is declared in a class called AudioClip. To use use it, you must use the full name 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:

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.

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. 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). If using Thread, the callback must be called in the main Thread. Just trying to keep this example simple.

Programmer
  • 121,791
  • 22
  • 236
  • 328
  • Thanks you guys !!! this has all been really helpful! Im giving everyone up votes!!!! – AlexC Nov 02 '16 at 04:36
  • You are welcome. You can't give upvotes because you don't have enough reputation to do so. The only you can do is to accept one of the answers you think helped you the most. [Here](http://meta.stackexchange.com/a/5235) is how to do that. – Programmer Nov 02 '16 at 04:40
1

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. 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:

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. 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(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. 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
}
Chuck Savage
  • 11,775
  • 6
  • 49
  • 69
  • 1
    Thanks guys im this has all been really helpful! im giving everyone up votes Best Of The Best Alex – AlexC Nov 02 '16 at 04:37