Inline Functions in C#

How to make inline functions in C#

Yes, C# supports that. There are several syntaxes available.

  • Anonymous methods were added in C# 2.0:

    Func<int, int, int> add = delegate(int x, int y)
    {
    return x + y;
    };
    Action<int> print = delegate(int x)
    {
    Console.WriteLine(x);
    }
    Action<int> helloWorld = delegate // parameters can be elided if ignored
    {
    Console.WriteLine("Hello world!");
    }
  • Lambdas are new in C# 3.0 and come in two flavours.

    • Expression lambdas:

      Func<int, int, int> add = (int x, int y) => x + y; // or...
      Func<int, int, int> add = (x, y) => x + y; // types are inferred by the compiler
    • Statement lambdas:

      Action<int> print = (int x) => { Console.WriteLine(x); };
      Action<int> print = x => { Console.WriteLine(x); }; // inferred types
      Func<int, int, int> add = (x, y) => { return x + y; };
  • Local functions have been introduced with C# 7.0:

    int add(int x, int y) => x + y;
    void print(int x) { Console.WriteLine(x); }

There are basically two different types for these: Func and Action. Funcs return values but Actions don't. The last type parameter of a Func is the return type; all the others are the parameter types.

There are similar types with different names, but the syntax for declaring them inline is the same. An example of this is Comparison<T>, which is roughly equivalent to Func<T, T, int>.

Func<string, string, int> compare1 = (l,r) => 1;
Comparison<string> compare2 = (l, r) => 1;
Comparison<string> compare3 = compare1; // this one only works from C# 4.0 onwards

These can be invoked directly as if they were regular methods:

int x = add(23, 17); // x == 40
print(x); // outputs 40
helloWorld(x); // helloWorld has one int parameter declared: Action<int>
// even though it does not make any use of it.

Inline functions in C#?

Finally in .NET 4.5, the CLR allows one to hint/suggest1 method inlining using MethodImplOptions.AggressiveInlining value. It is also available in the Mono's trunk (committed today).

// The full attribute usage is in mscorlib.dll,
// so should not need to include extra references
using System.Runtime.CompilerServices;

...

[MethodImpl(MethodImplOptions.AggressiveInlining)]
void MyMethod(...)

1. Previously "force" was used here. I'll try to clarify the term. As in the comments and the documentation, The method should be inlined if possible. Especially considering Mono (which is open), there are some mono-specific technical limitations considering inlining or more general one (like virtual functions). Overall, yes, this is a hint to compiler, but I guess that is what was asked for.

Creating Inline Functions and Macros

Inline functions in C#?

Finally in .NET 4.5, the CLR allows one to force1 method inlining
using MethodImplOptions.AggressiveInlining value. It is also available
in the Mono's trunk (committed today).

[MethodImplAttribute(MethodImplOptions.AggressiveInlining)] 
void Func()
{
Console.WriteLine("Hello Inline");
}

How to force inline functions in C#?

Sort of. It's not under your direct control to turn on for sure. It's never inlined in the IL - it's only done by the JIT.

You can explicitly force a method to not be inlined using MethodImplAttribute

[MethodImpl(MethodImplOptions.NoInlining)]
public void Foo() { ... }

You can also sort of "request" inlining as of .NET 4.5:

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Foo() { ... }

... but you can't force it. (Prior to .NET 4.5, that enum value didn't exist. See the .NET 4 documentation, for example.)

Inline functions in C#?

Finally in .NET 4.5, the CLR allows one to hint/suggest1 method inlining using MethodImplOptions.AggressiveInlining value. It is also available in the Mono's trunk (committed today).

// The full attribute usage is in mscorlib.dll,
// so should not need to include extra references
using System.Runtime.CompilerServices;

...

[MethodImpl(MethodImplOptions.AggressiveInlining)]
void MyMethod(...)

1. Previously "force" was used here. I'll try to clarify the term. As in the comments and the documentation, The method should be inlined if possible. Especially considering Mono (which is open), there are some mono-specific technical limitations considering inlining or more general one (like virtual functions). Overall, yes, this is a hint to compiler, but I guess that is what was asked for.

Inline function blocks in C#

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));

Passing object to an inline function in C#

You already have the solution:

f(nameof(Temperature), Temperature);

Because that information can't be inferred from this:

f(Temperature);

There'd be no way for the internals of f to know what variable name was used, or if one was used at all. What if you did this?:

f("123.45");
f(temperatures[0]);
f(someObj.GetTemperature());
f(await this.Temperatures.SingleOrDefaultAsync(t => t == "123.45"));

What would the "variable names" be?

That information isn't provided to the method, so you'll need to provide it manually if you need it. Basically, variables aren't passed to the method, values are.

Wrapping INLINE functions

inline: Tagging a method inline is an instruction to the compiler to not emit a function call, but to instead take the contents of the method, and put it directly into the calling function. I believe this is only advisory, the compiler can choose to emit a function call anyway. Regardless, you don't need to do anything fancy when calling this function from C++/CLI, so you don't need to do anything fancy when wrapping it. Just wrap it the same as any other method.

private variables: If they're private variables, then unmanaged C++ code using PABCon wouldn't have access to them. The public interface of PABCon is just the public methods, so that's all you need to worry about. (If the C++ class had any public variables, then you'd wrap them by creating a property in C++/CLI.)

~PABConWrapper: In C++/CLI, ~ is not the destructor, it's the dispose method. As implemented right now, you'll have a memory leak if you forget to dispose your new class. At a minimum, switch the ~ to !, and declare the finalizer instead. Ideally, implement both ! and ~, delete the unmanaged object in both methods (with a proper null check), and add proper null checks in the other methods. This would be a good & proper implementation of IDisposable.

Inline function definition

You can do like this

Func<int,bool> HasFullAccess = mask => mask % 2 == 1;


Related Topics



Leave a reply



Submit