// 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 );
}
};
}
}
Category: How To
Truncate Decimal Numbers without Rounding in C#
How to sanitize decimal numbers to the Nth decimal place without rounding.
For example, if you are dealing with crypto numbers like BTC (Bitcoin) or ETH (Etherium).
https://gist.github.com/Protiguous/14d51ba097783f249f1f3b441ed82674
Concat two arrays in C#
public static T[] Concat<T>( this T[] array1, T[] array2 ) {
var result = new T[ array1.LongLength + array2.LongLength ];
array1.CopyTo( result, 0 );
array2.CopyTo( result, array1.LongLength );
return result;
}
Create only 1 instance of an object per thread.
/// <summary>
/// Create only 1 instance of <see cref="T" /> per thread. (Only unique when using this method!)
/// </summary>
/// <typeparam name="T"></typeparam>
public static class Cache<T> where T : notnull, new() {
private static ThreadLocal<T> LocalCache { get; } = new(() => new T(), false);
public static T? Instance { get; } = LocalCache.Value;
}
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)
};
How to convert any object to a Boolean value in C#
/// <summary>
/// <para>Returns true if <paramref name="value" /> is a true, 'Y', "yes", "true", "1", or '1'.</para>
/// <para>Returns false if <paramref name="value" /> is a false, 'N', "no", "false", or '0'.</para>
/// <para>A null will return false.</para>
/// </summary>
/// <param name="value"></param>
[Pure]
public static Boolean ToBoolean<T>( [CanBeNull] this T value ) {
switch ( value ) {
case null: return false;
case Boolean b: return b;
case Char c: return c.In( ParsingConstants.TrueChars );
case Int32 i: return i >= 1;
case String s when String.IsNullOrWhiteSpace( s ): return false;
case String s: {
var clean = s.Trimmed();
if ( clean is null ) {
return false;
}
if ( clean.In( ParsingConstants.TrueStrings ) ) {
return true;
}
if ( Boolean.TryParse( clean, out var result ) ) {
return result;
}
break;
}
}
var t = value.ToString();
if ( !String.IsNullOrWhiteSpace( t ) ) {
t = t.Trim();
if ( t.In( ParsingConstants.TrueStrings ) ) {
return true;
}
if ( t.In( ParsingConstants.FalseStrings ) ) {
return false;
}
if ( Boolean.TryParse( t, out var rest ) ) {
return rest;
}
}
return false;
}
[DebuggerStepThrough]
[Pure]
public static Boolean? ToBooleanOrNull<T>( [CanBeNull] this T value ) {
switch ( value ) {
case null: return default( Boolean? );
case Boolean b: return b;
case Char c: return c.In( ParsingConstants.TrueChars );
case Int32 i: return i >= 1;
case String s when String.IsNullOrWhiteSpace( s ): return default( Boolean? );
case String s: {
var trimmed = s.Trimmed();
if ( trimmed is null ) {
return default( Boolean? );
}
if ( trimmed.In( ParsingConstants.TrueStrings ) ) {
return true;
}
if ( trimmed.In( ParsingConstants.FalseStrings ) ) {
return default( Boolean? );
}
if ( Boolean.TryParse( trimmed, out var result ) ) {
return result;
}
break;
}
}
var t = value.ToString();
if ( String.IsNullOrWhiteSpace( t ) ) {
return default( Boolean? );
}
t = t.Trim();
if ( t.In( ParsingConstants.TrueStrings ) ) {
return true;
}
if ( t.In( ParsingConstants.FalseStrings ) ) {
return default( Boolean? );
}
return Boolean.TryParse( t, out var rest ) ? rest : default( Boolean? );
}
public static Boolean ToBooleanOrThrow<T>( [CanBeNull] this T value ) =>
value.ToBooleanOrNull() ?? throw new FormatException( $"Unable to convert {nameof( value ).SmartQuote()} [{value}] to a boolean value." );
/// <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;
/// <summary>
/// N, 0, no, false, fail, failed, failure, bad
/// </summary>
[NotNull]
[ItemNotNull]
public static readonly String[] FalseStrings = {
"N", "0", "false", Boolean.FalseString, "fail", "failed", "stop", nameof( Status.Bad ), nameof( Status.Failure ), nameof( Status.No ),
nameof( Status.Negative )
};
/// <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)
};
How to get the Description Attribute in C#
[CanBeNull]
public static String? GetDescription<T>( [CanBeNull] this T e ) where T : IConvertible {
if ( e is not Enum ) {
return default( String? );
}
var type = e.GetType();
foreach ( Int32 val in Enum.GetValues( type ) ) {
if ( val != e.ToInt32( CultureInfo.InvariantCulture ) ) {
continue;
}
var ename = type.GetEnumName( val );
if ( ename is null ) {
continue;
}
var memInfo = type.GetMember( ename );
if ( memInfo[0].GetCustomAttributes( typeof( DescriptionAttribute ), false ).FirstOrDefault() is DescriptionAttribute descriptionAttribute ) {
return descriptionAttribute.Description;
}
}
return default( String? );
}
How to check the return Status in C#
public static class StatusExtensions {
static StatusExtensions() {
if ( Status.Good.IsBad() ) {
throw new InvalidOperationException( "Someone blinked." );
}
if ( Status.Failure.IsGood() ) {
throw new InvalidOperationException( "Someone blinked." );
}
if ( Status.Success.IsBad() ) {
throw new InvalidOperationException( "Someone blinked." );
}
if ( !Status.Unknown.IsUnknown() ) {
throw new InvalidOperationException( "Someone blinked." );
}
}
[Pure]
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public static Boolean Failed( this Status status ) => status <= Status.Failure;
[Pure]
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public static Boolean IsBad( this Status status ) => status.Failed();
[Pure]
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public static Boolean IsUnknown( this Status status ) => status == Status.Unknown || !status.IsBad() && !status.IsGood();
[Pure]
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public static Boolean Succeeded( this Status status ) => status >= Status.Success;
[Pure]
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public static Boolean IsGood( this Status status ) => status.Succeeded();
[Pure]
[NotNull]
public static String Symbol( this Status status ) => status.GetDescription() ?? Symbols.Null;
[Pure]
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public static Status ToStatus( this Boolean status ) => status ? Status.Success : Status.Failure;
}
How to Return Status in C#
I use the design pattern of returning a Status in a tuple with the exception or actual result I need to return like this,
return (Status.Success, result);
You don’t have to go “all out” like this Status example (I got bored one day).
Basically 0 is none, neutral, or unknown.
Anything less than 0 is a type of error.
And anything higher than 0 would be a type of success.
Example:
public enum Status : Int16 {
Fatal = -Flawless,
Exception = Error - 1,
Error = Warning - 1,
Warning = Skip - 1,
Skip = -Continue,
Timeout = Stop - 1,
Stop = -Start,
Halt = -Proceed,
Done = Negative - 1,
Negative = No - 1,
No = -Yes,
Bad = -Good,
Failure = -Success,
Unknown = 0,
None = Unknown,
Success = 1,
Okay = Success,
Good = Okay,
Yes = Good,
Positive,
Continue,
Go,
Start,
Proceed,
Advance,
Flawless
}
And some Status extensions I use.
public static class StatusExtensions {
static StatusExtensions() {
if ( Status.Good.IsBad() ) {
throw new InvalidOperationException( "Someone blinked." );
}
if ( Status.Failure.IsGood() ) {
throw new InvalidOperationException( "Someone blinked." );
}
if ( Status.Success.IsBad() ) {
throw new InvalidOperationException( "Someone blinked." );
}
if ( !Status.Unknown.IsUnknown() ) {
throw new InvalidOperationException( "Someone blinked." );
}
}
[Pure]
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public static Boolean Failed( this Status status ) => status <= Status.Failure;
[Pure]
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public static Boolean IsBad( this Status status ) => status.Failed();
[Pure]
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public static Boolean IsGood( this Status status ) => status.Succeeded();
[Pure]
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public static Boolean IsUnknown( this Status status ) => status == Status.Unknown || !status.IsBad() && !status.IsGood();
[Pure]
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public static Boolean Succeeded( this Status status ) => status >= Status.Success;
[Pure]
[NotNull]
public static String Symbol( this Status status ) => status.GetDescription() ?? Symbols.Null;
[Pure]
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public static Status ToStatus( this Boolean status ) => status ? Status.Success : Status.Failure;
}