Click here to Skip to main content
15,867,308 members
Articles / Programming Languages / C#
Tip/Trick

Abusing Extension Methods and Null Continuation

Rate me:
Please Sign up or sign in to vote.
5.00/5 (18 votes)
31 Dec 2019CPOL3 min read 16.6K   8   10
Please don't do this!

Introduction

Yet another crazy way to write if-then statements without writing if. Really, don't do this, it's just an experiment in what's possible. The main reason not to do this is that extension methods and the ?. null continuation operator were not intended for this purpose, and you'll confuse the heck out of other programmers when they encounter this crazy code.

The Basic If

The if statement is one of the cornerstones of a program, slightly more readable than its assembly language counterparts "branch if equal", "branch if not equal", "branch if greater", and so forth. In almost every language, you write the following, which tests the truth of the condition:

C#
if (somethingIsTrue)
{
  doSomethingWhenTrue();
}

For our little demonstration, we'll use this code:

C#
public void Test()
{
  if (true)
  {
    Write("The usual way");
  }
}

public void Write(string msg)
{
  Console.WriteLine(msg);
}

So far so good. Everyone can read that, even those without any programming experience!

WhenTrue

Now let's introduce an extension method:

C#
public static void WhenTrue(this bool condition, Action action)
{
  if (condition)
  {
    action();
  }
}

And now, using extension and anonymous methods, we can write:

C#
true.WhenTrue(() => Write("Using an extension method"));

Now we have something less readable unless you're familiar with anonymous methods (aka "fat arrow" methods) but you still get the basic idea -- The anonymous method, as an Action, is executed when the condition on the left is true, and:

C#
false.WhenTrue(() => Write("Should be false!!!"));

When not true, it doesn't. This works of course:

C#
int a = 1;
int b = 1;
(a == b).WhenTrue(() => Write("A equals B"));

But the () => syntax is a lot of arcane symbol incantation and what is occult in the anonymous method is that there is a hidden closure on this, such that the Write method is found in the class making the call.

Continue if Not Null

If we introduce a different extension method:

C#
public static T WhenTrue<T>(this bool condition, T me) where T : class
{
  return condition ? me : default(T);
}

lo-and-behold, we can write:

C#
true.WhenTrue(this)?.Write("Using null continuation");
false.WhenTrue(this)?.Write("Should also be false!!!");

Oh my. Now we have entered into the land of occult initiation that the materialist developer cannot immediately understand and will (with good reason) deny even exists! Why are we passing in this? Why does the extension method return null? How is it possible to continue with a method of the class?

In the occult school of programming, the beauty of this is that this is returned by the extension method when the condition is true, and with the arcane knowledge that T is a class, default(T) always returns null!

Where Do You Want This?

The above syntax is sort of backwards, particularly since this is a parameter of WhenTrue, which makes reading the code a bit like reading Reverse Polish Notation. Let's try this instead:

C#
public static T WhenTrue<T>(this T me, bool condition) where T : class
{
  return condition ? me : default(T);
}

Funny how the implementation of the extension method is exactly the same, all we've done is swapped the parameters such that instead of the extension method being available to a bool type, it's available to any class type. So now we can write something a wee bit more left-to-right:

C#
this.WhenTrue(true)?.Write("Another truth");
this.WhenTrue(false)?.Write("Another falsehood");

Coalesce Your Ascension or Else!

So what about the else, a necessary kindred spirit of if? Well, try this, using the null coalescence operator:

C#
var _ = this.WhenTrue(true)?.Write("Another truth") ?? Write("Not truth");
var __ = this.WhenTrue(false)?.Write("Another falsehood") ?? Write("False!");

This bit of magic requires that Write returns a value and that we assign that value to something we probably don't care about, so Write now looks like this:

C#
public int Write(string msg)
{
  Console.WriteLine(msg);
  return 0;
}

Truly, we have entered into the realm of the esoteric!

And Thus...

We conclude the year 2019 with how extension methods and null continuation operators can ascend to do something the designers probably never intended.

The grand master of coding will also note that statements like:

C#
this.WhenTrue(true)?.Console.WriteLine("Go to h***");

are not possible because, of course, Console is not a member of this unless you write a static member of this called Console that wraps the functionality of System.Console...run away!

History

  • 31st December, 2019: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Interacx
United States United States
Blog: https://marcclifton.wordpress.com/
Home Page: http://www.marcclifton.com
Research: http://www.higherorderprogramming.com/
GitHub: https://github.com/cliftonm

All my life I have been passionate about architecture / software design, as this is the cornerstone to a maintainable and extensible application. As such, I have enjoyed exploring some crazy ideas and discovering that they are not so crazy after all. I also love writing about my ideas and seeing the community response. As a consultant, I've enjoyed working in a wide range of industries such as aerospace, boatyard management, remote sensing, emergency services / data management, and casino operations. I've done a variety of pro-bono work non-profit organizations related to nature conservancy, drug recovery and women's health.

Comments and Discussions

 
QuestionI can see so much more clearly now! Pin
jediYL1-Jan-20 11:33
professionaljediYL1-Jan-20 11:33 
AnswerRe: I can see so much more clearly now! Pin
Marc Clifton2-Jan-20 2:10
mvaMarc Clifton2-Jan-20 2:10 
GeneralMy vote of 1 Pin
mag131-Jan-20 0:39
mag131-Jan-20 0:39 
GeneralRe: My vote of 1 Pin
Marc Clifton1-Jan-20 6:37
mvaMarc Clifton1-Jan-20 6:37 
Questionforeachifnotnull Pin
kalberts31-Dec-19 13:06
kalberts31-Dec-19 13:06 
AnswerRe: foreachifnotnull Pin
Marc Clifton1-Jan-20 6:43
mvaMarc Clifton1-Jan-20 6:43 
GeneralRe: foreachifnotnull Pin
Luis Perez Garcia1-Jan-20 21:47
Luis Perez Garcia1-Jan-20 21:47 
In a ideal world, a list whitout content can be empty but it should never be null.
However, when dealing with legacy code, you must be ready for any non-documented behaviour and take it in account to avoid run-time exceptions (or fail early with a custom error message so you can fix the issue ASAP).
Also, making too many extension methods on "commonly used classes" (as System.String) can pollute the global namespace (maybe you should mention this in your article). So, it is preferable to add a method to your own class or create a derived one if you doesn't "own" the source code.
However, if the class is sealed, an extension method can made you happy again Smile | :)

Keep writing, sir.
GeneralRe: foreachifnotnull Pin
Marc Clifton2-Jan-20 11:19
mvaMarc Clifton2-Jan-20 11:19 
QuestionEnhance what to no tdo Pin
Xequence31-Dec-19 6:31
Xequence31-Dec-19 6:31 
GeneralMy vote of 5 Pin
Eek Ten Bears30-Dec-19 20:26
Eek Ten Bears30-Dec-19 20:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.