The function Apply()

The function Apply()

You may find one of these patterns while looking through C# code:

byte[] Read(int length)
{
  var data = new byte[length];
  stream.Read(data, 0, length);
  return data;
}

using var rng = new RNGCryptoServiceProvider();
var salt = new byte[8];
rng.GetBytes(salt);

var stdin = process.StandardInput;
if (stdin != null)
{
  stdin.Write(text ?? "");
  stdin.Close();
}

There is a function that I consider useful. It joins initialisation and usage, removes null checks, and simplifies variable management.

This is the object extension function Apply():

public static class ObjectExtensions {
  public static T Apply<T>(this T value, Action<T> action) {
    if (!EqualityComparer<T>.Default.Equals(value, default)) action(value);
    return value;
  }
}

It kind of applies a side effect to the data and returns the data, unless it is null (default). Think about it as a sister function to "?.", but as "?." only calls the method when the value is not null, Apply() allows to apply any modificator when the value is not null.

Let's see how it modifies these code fragments:

byte[] Read(int length) =>
  new byte[length].Apply(_ => stream.Read(_, 0, length));

using var rng = new RNGCryptoServiceProvider();
var salt = new byte[8].Apply(rng.GetBytes);

process.StandardInput.Apply(stdin => {
  stdin.Write(text);
  stdin.Close();
});

It is quite useful for fluent APIs. Instead of returning this at the end of every method, you can use expression-bodied members and Apply:

public class Builder
{
  private string _name;
  private string _address;
  private string _notes;
  
  public Builder Name(string name)
  {
    _name = name;
    return this;
  }
  
  public Builder Address(string address)
  {
    _address = address;
    return this;
  }
  
  public Builder Notes(string notes)
  {
    _notes = notes;
    return this;
  }
  
  ...
}

And with Apply():

public class Builder
{
  private string _name;
  private string _address;
  private string _notes;
  
  public Builder Name(string name) =>
    this.Apply(_ => _name = name);

  public Builder Address(string address) =>
    this.Apply(_ => _address = address);

  public Builder Notes(string notes) =>
    this.Apply(_ => _notes = notes);

  ...
}