How to make an Action run only X count of times in C#?

// Copyright © Protiguous. All Rights Reserved.
//
// This entire copyright notice and license must be retained and must be kept visible in any binaries, libraries,
// repositories, or source code (directly or derived) from our binaries, libraries, projects, solutions, or applications.
//
// All source code belongs to [email protected] unless otherwise specified or the original license has
// been overwritten by formatting. (We try to avoid it from happening, but it does accidentally happen.)
//
// Any unmodified portions of source code gleaned from other sources still retain their original license and our thanks goes to those Authors.
// If you find your code unattributed in this source code, please let us know so we can properly attribute you and include the proper licenses and/or copyrights.
// If you want to use any of our code in a commercial project, you must contact [email protected] for permission, license, and a quote.
//
// Donations, payments, and royalties are accepted via bitcoin: 1Mad8TxTqxKnMiHuZxArFvX8BuFEB9nqX2 and PayPal: [email protected]
//
// ====================================================================
// Disclaimer:  Usage of the source code or binaries is AS-IS.
// No warranties are expressed, implied, or given.
// We are NOT responsible for Anything You Do With Our Code.
// We are NOT responsible for Anything You Do With Our Executables.
// We are NOT responsible for Anything You Do With Your Computer.
// ====================================================================
//
// Contact us by email if you have any questions, helpful criticism, or if you would like to use our code in your project(s).
// For business inquiries, please contact me at [email protected]
// Our software can be found at "https://Protiguous.com/Software/"
// Our GitHub address is "https://github.com/Protiguous".
//
// File "DelegateExtensions.cs" last formatted on 2022-04-07 at 12:38 PM by Protiguous.

public static class DelegateExtensions {

	private sealed class ContextCallOnlyXTimes {
		internal Int64 CallsAllowed;

		public ContextCallOnlyXTimes( Int64 times ) {
			if ( times <= 0 ) {
				times = 0;
			}
			this.CallsAllowed = times;
		}
	}

	/// <summary>Only allow a delegate to run X times.</summary>
	/// <param name="action"></param>
	/// <param name="callsAllowed"></param>
	/// <example>var barWithBarrier = ActionBarrier(Bar, remainingCallsAllowed: 2 );</example>
	/// <remarks>Calling the delegate more often than <paramref name="callsAllowed" /> should just NOP.</remarks>
	public static Action ActionBarrier( this Action action, Int64 callsAllowed = 1 ) {
		var context = new ContextCallOnlyXTimes( callsAllowed );

		return () => {
			if ( Interlocked.Decrement( ref context.CallsAllowed ) >= 1 ) {
				action();
			}
		};
	}

	/// <summary>Only allow a delegate to run X times.</summary>
	/// <param name="action"></param>
	/// <param name="parameter"></param>
	/// <param name="callsAllowed"></param>
	/// <example>var barWithBarrier = ActionBarrier(Bar, remainingCallsAllowed: 2 );</example>
	/// <remarks>Calling the delegate more often than <paramref name="callsAllowed" /> should just NOP.</remarks>
	public static Action ActionBarrier<T>( this Action<T?> action, T? parameter, Int64 callsAllowed = 1 ) {
		var context = new ContextCallOnlyXTimes( callsAllowed );

		return () => {
			if ( Interlocked.Decrement( ref context.CallsAllowed ) >= 1 ) {
				action( parameter );
			}
		};
	}
}

Premature optimization is the root of all evil.. NOT!

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.

Famous computer scientist Donald Knuth

His quote is often clipped down to just “premature optimization is the root of all evil”, but that is NOT TRUE.

Yes, don’t micro-benchmark everything when you begin a project, but please do think ahead. And once you’ve got the program working as intended, then make it faster by profiling and looking for the bottlenecks.

Choose the proper data structures. Array? List? Hashset? Queue? Dictionary? Caching?
Take a few moments and think it over.

How often will this line of code be ran? Do I need to inline it, or pull it out into a separate method?

Some useful C# Swap methods

public static class SwapExt
{
	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void Swap<T>(ref T? left, ref T? right) => (left, right) = (right, left);

	[Pure]
	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static (T? right, T? left) Swap<T>(this T? left, T? right) => (right, left);

	[Pure]
	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static (T? right, T? left) Swap<T>((T? left, T? right) tuple) => (tuple.right, tuple.left);
}

Pay close attention to which method you think is being used. (The refs versus the tuples.)

C# null coalescing operator, ??

C# has a nice ?? operator that can be chained.
In a statement, it will return the first non-null value or null if none are found to not be null.

For example, if you had the code:

string? value1 = null;
string? value2 = nameof(value2);
string? result = value1 != null ? value1 : value2;

The last line could be simplified down to:

string result = value1 ?? value2;

As far as I know, there is no limit on how many ?? can be chained!

How to [Smartly] add SQL Braces in C#

If you need a SQL object correctly quoted by the [ and ] braces.

		/// <summary>
		///     Add the left [ and right ] braces if they're not already on the string.
		///     <para>An empty or whitepsace string throws <see cref="ArgumentEmptyException"/>.</para>
		/// </summary>
		/// <param name="self"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentEmptyException"></exception>
		[DebuggerStepThrough]
        [NotNull]
        [Pure]
        public static String SmartBraces( [NotNull] this String? self ) {
            self = self.Trimmed();

            if ( String.IsNullOrEmpty( self ) ) {
	            throw new ArgumentEmptyException( nameof( self ) );
            }

			if ( self.StartsWith( "[", StringComparison.Ordinal ) && self.EndsWith( "]", StringComparison.Ordinal ) ) {
	            self = self[ 1..^1 ]?.Trim();
            }

            if ( String.IsNullOrEmpty( self ) ) {
	            throw new ArgumentEmptyException( nameof( self ) );
			}

			return $"{'['}{self}{']'}";
        }

		/// <summary>Trim the ToString() of the object; returning null if null, empty, or whitespace.</summary>
		/// <param name="self"></param>
		/// <returns></returns>
		[DebuggerStepThrough]
		[CanBeNull]
		[Pure]
		public static String? Trimmed<T>( [CanBeNull] this T self ) =>
			self switch {
				null => default( String? ),
				String s => s.Trim().NullIfEmpty(),
				var _ => self.ToString()?.Trim().NullIfEmpty()
			};


		/// <summary>Returns null if <paramref name="self" /> is <see cref="String.IsNullOrEmpty" />.</summary>
		/// <param name="self"></param>
		/// <returns></returns>
		[CanBeNull]
		[DebuggerStepThrough]
		[Pure]
		public static String? NullIfEmpty( [CanBeNull] this String? self ) => String.IsNullOrEmpty( self ) ? null : self;


//Note: All attributes can be removed.

Boolean Parsing Constants in C#

		/// <summary>
		/// N, 0, no, false, fail, failed, failure, bad
		/// </summary>
		[NotNull]
		[ItemNotNull]
		public static readonly String[] FalseStrings = {
			"N", "0", "no", "false", Boolean.FalseString, "fail", "failed", "failure", "bad"
		};

		/// <summary>
		/// Y, 1
		/// </summary>
		[NotNull]
		public static readonly Char[] TrueChars = {
			'Y', '1'
		};

		/// <summary>
		/// Y, 1, yes, true, Success, good, Go, Positive, Continue
		/// </summary>
		[NotNull]
		[ItemNotNull]
		public static readonly String[] TrueStrings = {
			"Y", "1", "yes", "true", Boolean.TrueString, nameof( Status.Success ), "good", nameof( Status.Go ), nameof( Status.Positive ), nameof( Status.Continue ), nameof(Status.Okay)
		};