DEV Community

Cover image for Action-Oriented C#

Action-Oriented C#

Matt Eland on September 16, 2019

Five years ago I hit a plateau. My code hit a certain level of quality and flexibility and stopped improving. Here's how I used aspects of function...
Collapse
 
seangwright profile image
Sean G. Wright

I once tried to build out a very functional API in C# using partial application, currying, delegates, ect... ect...

It was a lot of fun but left me with code I couldn't understand when I came back to it several months later.

I do love the power of higher order functions in C# but the language syntax makes it noisy and it feels out of place next to all the Object Oriented code.

Often, instead of passing around delegates, if I want to implement something like the strategy pattern, I'll make a single method interface - since this is effectively the same thing as a function.

Then I don't have to worry about the generic delegates Func<...> and Action<...> and my interface's signature is more like the rest of the code base (and easier for other developers to reason about).

That said, I do love exploring these functional approaches as they help me think about the different ways to solve problems.

I guess it's all up to your personal taste and the taste of your team!

Thanks for the post 🙏.

Collapse
 
integerman profile image
Matt Eland

I agree with the syntax issues. TypeScript has type aliases where you can name a union of types for example. .NET cod use something similar.

That said, some of the most flexible aspects of .net and many popular libraries rely on Action and Func under the covers. Thankfully the syntax to invole a lambda expression is cleaner than the parameter signature definition.

Collapse
 
smartcodinghub profile image
Oscar • Edited

You can use delegates or functional interfaces to have alias.

A functional interface is an interface with only one method, as suggested above.

With the delegate, you can have:

public delegate decimal CalculateScore();

This is totally compatible with Lambdas and Funcs. And a safe way to do a Strategy Pattern like you want.

Collapse
 
seangwright profile image
Sean G. Wright

Yah, definitely didn't want it to seem like I dislike them or avoid them.

I tend to use them for internal APIs and infrastructure code - less so for business logic service methods.

I just saw on Twitter today that someone is actively championing discriminated unions for C# 9 😁:

Both TypeScript's and F#'s allowance of not explicitly typing params and return types helps reduce that function + generic noise.

We could do the aliasing with C# named delegates, but then we are kinda just trading one noise for another (with more type limitations).

Collapse
 
bugmagnet profile image
Bruce Axtens

Y'got some typos in the code to fix. Otherwise great article.

Collapse
 
integerman profile image
Matt Eland

Thanks. Only serves to highlight the dangers of copy-paste driven development. :-)