JustArchiNET.Madness 2.3.2

Additional Details

Due to the fact that we've dropped support for .NET Framework in our other projects, we don't intend to develop Madness further. You're free to fork or re-use Madness components if you find them useful!

There is a newer version of this package available.
See the version list below for details.
dotnet add package JustArchiNET.Madness --version 2.3.2
NuGet\Install-Package JustArchiNET.Madness -Version 2.3.2
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="JustArchiNET.Madness" Version="2.3.2" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add JustArchiNET.Madness --version 2.3.2
#r "nuget: JustArchiNET.Madness, 2.3.2"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install JustArchiNET.Madness as a Cake Addin
#addin nuget:?package=JustArchiNET.Madness&version=2.3.2

// Install JustArchiNET.Madness as a Cake Tool
#tool nuget:?package=JustArchiNET.Madness&version=2.3.2

☠️ Madness

Build status (GitHub) Github last commit date NuGet Total downloads License

GitHub stable release version NuGet stable release version GitHub stable release date

GitHub experimental release version NuGet experimental release version GitHub experimental release date

GitHub sponsor Patreon support

Crypto donate PayPal.me donate PayPal donate Revolut donate Steam donate


Repobeats analytics image


Description

Madness embraces your project by including compatibility layer for selected APIs normally not available on .NET Framework target.

Installation

We support netstandard2.0, so .NET Framework 4.6.1 and newer.

dotnet add package JustArchiNET.Madness

If you're targetting multiple frameworks out of which only one is .NET Framework (e.g. net5.0 and net48), it's usually a good idea to not pull it for the others.

<ItemGroup Condition="'$(TargetFramework)' == 'net48'">
	<PackageReference Include="JustArchiNET.Madness" />
</ItemGroup>

Usage

Usage depends on where you need to go mad. It'll require from you to add appropriate using clause in the affected source files.

Hint

Instead of adding using clause to each file, you can instead decide to do it once in the csproj (or appropriate project declaration) file. This way you won't need to add #if NETFRAMEWORK only for using JustArchiNET.Madness(...) clauses.

Example:

<ItemGroup Condition="'$(TargetFramework)' == 'net48'">
	<PackageReference Include="JustArchiNET.Madness" />

	<Using Include="JustArchiNET.Madness" />
	<Using Include="JustArchiNET.Madness.EnvironmentMadness.Environment" Alias="Environment" />
	<Using Include="JustArchiNET.Madness.FileMadness.File" Alias="File" />
	<Using Include="JustArchiNET.Madness.HashCodeMadness.HashCode" Alias="HashCode" />
	<Using Include="JustArchiNET.Madness.HMACSHA1Madness.HMACSHA1" Alias="HMACSHA1" />
	<Using Include="JustArchiNET.Madness.OperatingSystemMadness.OperatingSystem" Alias="OperatingSystem" />
	<Using Include="JustArchiNET.Madness.PathMadness.Path" Alias="Path" />
	<Using Include="JustArchiNET.Madness.RandomMadness.Random" Alias="Random" />
	<Using Include="JustArchiNET.Madness.SHA256Madness.SHA256" Alias="SHA256" />
	<Using Include="JustArchiNET.Madness.StringMadness.String" Alias="String" />
</ItemGroup>

We recommend to add <Using> clauses only for parts that you actually require/want to use from Madness.

Because of the File using declared above, you're now able to write this very nice ifdef-free code for both net48 and newer platform target:

using System.IO;
using System.Threading.Tasks;

namespace ThisIsMadness {
	public static class ThisIsSparta {
		public static async Task Scream() {
			// This compiles for both .NET Framework and other targets without any #if clauses, nice
			await File.WriteAllTextAsync("example.txt", "example").ConfigureAwait(false);
		}
	}
}

Static extensions

Static extensions include useful stuff that you'll usually stumble upon with newer language syntax and/or .NET platform.

Examples include native deconstruction (for all types), DisposeAsync() as well as support for await using { } blocks, or methods working with ReadOnlyMemory.

#if NETFRAMEWORK
using JustArchiNET.Madness;
#endif
using System.IO;
using System.Threading.Tasks;

namespace ThisIsMadness {
	public static class ThisIsSparta {
		public static async Task Scream() {
			MemoryStream stream = new MemoryStream();

			// Wow, this compiles now, but .NET Framework can't into `IAsyncDisposable`!
			// HOW IS THIS POSSIBLE, THIS IS MADNESS ☠️
			await stream.DisposeAsync().ConfigureAwait(false);
		}
	}
}

IndexRange

This library includes a dependency on awesome IndexRange project, which allows you to use System.Index and System.Range on .NET Framework.

namespace ThisIsMadness {
	public static class ThisIsSparta {
		public static void Scream() {
			const string text = "Madness?";

			string? subString = text[1..^1];
		}
	}
}

Check IndexRange project for more details.

File extensions

File extensions include mostly Async overloads for selected methods.

#if NETFRAMEWORK
using File = JustArchiNET.Madness.FileMadness.File;
#else
using System.IO;
#endif
using System.Threading.Tasks;

namespace ThisIsMadness {
	public static class ThisIsSparta {
		public static async Task Scream() {
			// This compiles for both .NET Framework and other targets without more #if clauses, nice
			await File.WriteAllTextAsync("example.txt", "example").ConfigureAwait(false);
		}
	}
}

HashCode extensions

HashCode extensions include implementation of Combine<T1, T2...>().

#if NETFRAMEWORK
using HashCode = JustArchiNET.Madness.HashCodeMadness.HashCode;
#else
using System;
#endif

namespace ThisIsMadness {
	public static class ThisIsSparta {
		public static void Scream() {
			int example = HashCode.Combine("test", "test2", "test3");
		}
	}
}

Path extensions

Path extensions include fully backported implementation of Path.GetRelativePath(), including more complex scenarios than below.

#if NETFRAMEWORK
using Path = JustArchiNET.Madness.PathMadness.Path;
#else
using System.IO;
#endif

namespace ThisIsMadness {
	public static class ThisIsSparta {
		public static void Scream() {
			// This compiles for both .NET Framework and other targets without more #if clauses, nice
			string example = Path.GetRelativePath("/tmp", "/tmp/example/example.txt");
		}
	}
}

OperatingSystem extensions

OperatingSystem extensions include implementation of IsFreeBSD(), IsLinux(), IsMacOS(), IsOSPlatform(), IsWindows() and alike.

Those functions should be compatible with platforms supported by Mono, for checking against Mono-specific platforms use IsOSPlatform(string platform), the exact names to check against can be found here.

#if NETFRAMEWORK
using OperatingSystem = JustArchiNET.Madness.OperatingSystemMadness.OperatingSystem;
#endif
using System;

namespace ThisIsMadness {
	public static class ThisIsSparta {
		public static void Scream() {
			if (OperatingSystem.IsWindows()) {
				// Windows logic
			} else {
				// Non-windows logic
			}
		}
	}
}

Other

Root JustArchiNET.Madness namespace also includes selected classes normally not available on .NET Framework, for example SupportedOSPlatform or non-generic TaskCompletionSource.

#if NETFRAMEWORK
using JustArchiNET.Madness;
#else
using System.Runtime.Versioning;
#endif

namespace ThisIsMadness {
	public static class ThisIsSparta {
		[SupportedOSPlatform("Windows")]
		public static void Scream() {
			// Obviously this doesn't have the effect you expect from your IDE, but at least you don't have to hide it behind #if
			// Besides, if you're targetting something else like net5.0 then it'll work as designed warning you about calls from other platforms.
		}
	}
}

FAQ

Do I need that #if NETFRAMEWORK clause?

If you're building only for .NET Framework exclusively, no, it's not required and actually quite useless code verbosity for you.

However, if you're targetting multiple frameworks out of which only one is .NET Framework (e.g. net5.0 and net48), then #if clause guarantees that madness won't embrace your other targets.

You don't want madness to embrace your other targets, do you?

It also becomes mandatory if you're building for multiple targets and you've followed our advice and conditionally included <PackageReference> only for .NET Framework. Other targets won't know about this namespace, so hiding the usage behind #if becomes obligatory. On the other hand, it's perfect, because it ensures you don't use our using where you don't intend to.

At the same time check out our hint above, as it's possible to add using clauses globally to the whole project, which won't require from you to pollute every file with a potential #if.

And what happens if I use Madness for other frameworks?

Nothing bad, if you ignore increased likelihood for compatibility issues, degraded performance, potential source code conflicts with original classes and all other mess that you really don't want to get into. Don't go deeper than you have to. We've been there before you, it's not pleasant. It's best to keep it sane for other targets, but we don't judge you, Madness supports netstandard2.0 and above, include it wherever you want to.

What if I need to combine Madness parts with .NET ones?

We've hidden our static classes deeper in our namespace for a reason - to decrease chance that you run into this issue. Usually it's enough for one #if on the top, as in our file extensions example above.

However, sometimes you can't help it, and you'll have to #if all the way through for those cases, still better than writing it yourself, right?

#if NETFRAMEWORK
using JustArchiNET.Madness;
#else
using System.Diagnostics;
#endif
using System;

namespace ThisIsMadness {
	public static class ThisIsSparta {
		internal static DateTime ProcessStartTime {
#if NETFRAMEWORK
			get => RuntimeMadness.ProcessStartTime.ToUniversalTime();
#else
			get {
				using Process process = Process.GetCurrentProcess();

				return process.StartTime.ToUniversalTime();
			}
#endif
		}
	}
}

If all else fails, you can in theory call Madness parts exclusively (since it's based on .NET Standard, not Framework per-se), so the above is rather a "perfect" example for not affecting your other targets negatively. You have to decide yourself between affecting code readability or compatibility and performance. Choose your poison. We recommend to keep Madness contained in .NET Framework exclusively, like in all our examples.

All of this is cool, but I'm missing XYZ for my needs...

Send a PR, Madness by default includes parts that we require ourselves in ArchiSteamFarm project and as you can guess, we can't rewrite everything that was made by thousands of developers in newer versions of .NET just to satisfy .NET Framework on its last leg.

For best results you should include exact classes, methods, properties and everything else, so source code requirements to make use of it are close to minimum and hopefully only initial using clause will be required to embrace the Madness.

We're also open for so-called "proxy" features in static classes that we already provide, to decrease burden of putting #if clauses everywhere. We've included all of those we require ourselves, such as:

public static class File {
	public static bool Exists(string? path) => System.IO.File.Exists(path);
}

This allows consumers to alias File to our implementation without additional burden - feel free to send a PR for those as well. If it helps you in any way to increase code quality and sanity for your original projects, Madness doesn't mind to take a hit for justified reason ☠️.


Attribution

Skull icon made by Freepik from Flaticon.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on JustArchiNET.Madness:

Package Downloads
ArchiSteamFarm.Library

ASF is a C# application with primary purpose of idling Steam cards from multiple accounts simultaneously.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
3.17.0 1,459 10/21/2023
3.16.0 2,417 9/13/2023
3.15.0 4,597 5/24/2023
3.14.0 308 5/17/2023
3.13.0 234 5/16/2023
3.12.0 822 4/20/2023
3.11.0 3,106 2/9/2023
3.10.0 1,174 1/12/2023
3.9.0 3,324 12/15/2022
3.8.0 4,049 10/27/2022
3.7.0 11,603 7/2/2022
3.6.0 2,853 6/19/2022
3.5.2 5,327 4/22/2022
3.5.1 1,220 4/13/2022
3.5.0 411 4/13/2022
3.4.0 877 4/2/2022
3.3.0 4,144 2/18/2022
3.2.1 5,104 1/23/2022
3.2.0 431 1/22/2022
3.1.1 3,801 12/12/2021
3.1.0 267 12/12/2021
3.0.0 3,023 12/4/2021
2.4.1 1,251 11/29/2021
2.4.0 1,209 11/29/2021
2.3.2 1,114 11/19/2021
2.3.1 702 11/19/2021
2.3.0 737 11/19/2021
2.2.1 380 11/18/2021
2.2.0 311 11/18/2021
2.1.0 372 11/17/2021
2.0.0 434 11/13/2021
2.0.0-alpha5 240 11/11/2021
2.0.0-alpha4 264 11/11/2021
2.0.0-alpha3 245 11/11/2021
2.0.0-alpha2 415 11/8/2021
2.0.0-alpha1 237 11/8/2021
1.5.0 870 11/8/2021
1.4.0 1,186 10/22/2021
1.3.1 1,892 9/5/2021
1.3.0 6,284 8/23/2021
1.2.0 495 8/19/2021
1.1.0 774 8/9/2021
1.0.0 438 8/7/2021
0.3.0 454 8/7/2021
0.2.0 380 8/5/2021
0.1.0 461 8/5/2021