Inline function blocks in C#

7.6k Views Asked by At

Using the dotween library for Unity: http://dotween.demigiant.com/documentation.php

And being rusty on C#...

Is there a way to specify a function inline as parameter to .OnComplete for instance, so that we don't have to chop up a sequence of actions in separate functions?

Ie I'd like to use the feature known as blocks in ObjC, but in C#.

Long-winded an unintuitive way:

void myCallback () {
   // do more stuff here
}
void mysequence() {
    transform.DOMoveX(4, 1).OnComplete(myCallback);
}

What I want to do which is easier to read and keeps stuff in place:

void mysequence() {
    transform.DOMoveX(4, 1).OnComplete({
        // do more stuff here
    });
}
4

There are 4 best solutions below

0
On BEST ANSWER

The way C# does this is with lambdas:

void mysequence() {
    transform.DOMoveX(4, 1).OnComplete(() => {
        // do more stuff here
    });
}

From the documentation you linked to:

// Callback without parameters
transform.DOMoveX(4, 1).OnComplete(myCallback);
// Callback with parameters
transform.DOMoveX(4, 1).OnComplete(()=>myCallback(someParam, someOtherParam));
0
On

You are looking for C# statement lambdas.

void mysequence() {
    transform.DOMoveX(4, 1).OnComplete(() => {
        // do more stuff here
    });
}
0
On

Use anonymous lambda functions:

void mysequence() {
    transform.DOMoveX(4, 1).OnComplete(() => {/*code goes here*/});
}

() => {}; is an anonymous function that take no arguments and returns nothing.

a => a is an anonymous function that takes one parameter and returns it.

Anonymous functions in c# can be closures, i.e. the functions can modify variables declared external to them.

var a = 0;

var f = () => a++;

f();

f();

// a is now 2
0
On

On a more general note, in addition to the answers that are already given, C#/.NET contains the notion of delegates that are kind a like function-pointers. You can define your own delegate-types by defining a method's signature like so:

delegate ReturnType MethodPointer(ParamTypeA paramA, ParamTypeB paramB);

Then you can assign methods as function-pointers like so:

private ReturnType SomeMethod(ParamTypeA paramA, ParamTypeB paramB)
{
    ...
}

MethodPointer = SomeMethod;

or pass it as a callback to another function/method:

private void OnComplete(MethodPointer callback)
{
   ...
}

OnComplete(SomeMethod);

Since declaring delegates this way can be quite time-consuming and cltter the code, they came up with generic delegate types: Action<...> (for void methods) and Func<...> (for method with a return type). Now you can simply say:

Func<ParamTypeA, ParamTypeB, ReturnType> func = SomeMethod;

without having to explicitly define the custom MethodPointer-delegate.

Lambda-expressions, as mentioned in the other posts, make it even easier to instantiate delegates by letting you define inline-like functions, so that you can define the implementation of SomeMethod() directly inside the call to OnComplete(), for example:

private void OnComplete(Action<ParameterType> callback)
{
}

OnComplete(parameter =>
{
   // implementation goes here...
});

Another advantage of working with lambda's is that the implementations can access local varirables.