Epiforge.Extensions.Components
4.4.0
dotnet add package Epiforge.Extensions.Components --version 4.4.0
NuGet\Install-Package Epiforge.Extensions.Components -Version 4.4.0
<PackageReference Include="Epiforge.Extensions.Components" Version="4.4.0" />
<PackageVersion Include="Epiforge.Extensions.Components" Version="4.4.0" />
<PackageReference Include="Epiforge.Extensions.Components" />
paket add Epiforge.Extensions.Components --version 4.4.0
#r "nuget: Epiforge.Extensions.Components, 4.4.0"
#:package Epiforge.Extensions.Components@4.4.0
#addin nuget:?package=Epiforge.Extensions.Components&version=4.4.0
#tool nuget:?package=Epiforge.Extensions.Components&version=4.4.0
Property Change Notification
This library offers the PropertyChangeNotifier class, which you may inherit from to quickly get all the property utilities we're all tired of copying and pasting everywhere.
Just call the protected OnPropertyChanged and OnPropertyChanging methods at the appropriate times from setters and compiler services will figure out what property you're in.
Or, if all you need to do is set the value of a field, SetBackedProperty couldn't make it any easier or convenient to handle that as efficiently as possible.
DynamicPropertyChangeNotifier is also available if your class needs to be dynamic.
Be sure to set the protected Logger property if you want the abstract class to log what's going on with property change notification.
Disposal
This library features base classes that handle things we've written a thousand times over, this time involving disposal.
If you want to go with an implementation of the tried and true IDisposable, just inherit from SyncDisposable.
Want a taste of the new IAsyncDisposable? Then, inherit from AsyncDisposable.
Or, if you want to support both, there's Disposable.
Additionally, if your object needs to be dynamic, you can use DynamicSyncDisposable, DynamicAsyncDisposable, or DynamicDisposable.
And if your object has no unmanaged resources to release and no need to announce its disposal as a property change, there are PlainSyncDisposable, PlainAsyncDisposable, and PlainDisposable, which keep the disposal claim, the events, and the ability to override disposal, but are not property change notifiers and declare no finalizer, which makes them meaningfully smaller.
Because they have no finalizer, nothing at all happens if disposal is neglected, so hold unmanaged resources in a SafeHandle or use one of the classes above; their synchronous method is DisposeCore, which takes no argument, because without a finalizer nothing could pass false.
Each of these features abstract methods to actually do your disposal.
On Disposable and DynamicDisposable, the asynchronous one, DisposeAsyncCore, is virtual and defaults to the synchronous Dispose(bool), so a type whose cleanup is entirely synchronous only writes it once.
On AsyncDisposable and DynamicAsyncDisposable it stays abstract, because there is no synchronous path for it to delegate to.
But all of the base classes feature:
- proper implementation of the finalizer and use of
GC.SuppressFinalize, save for the plain classes, which declare no finalizer - monitored access to disposal to ensure it can't happen twice
- the ability to override or "cancel" disposal by returning false from the abstract methods (e.g. you're reference counting and only want to dispose when your counter reaches zero)
- a protected
ThrowIfDisposedmethod you can call to before doing anything that requires you haven't been disposed - an
IsDisposedproperty the value of which is handled for you, along with its change notifications on all but the plain classes
This library provides the IDisposalStatus interface, which defines the IsDisposed property and all the base classes implement it.
This library also provides the INotifyDisposing, INotifyDisposed, and INotifyDisposalOverridden interfaces, which add events that notify of these occurrences.
Be sure to set the protected Logger property if you want the abstract class to log what's going on with disposal; the plain classes do not log, which is part of what makes them smaller.
Reflection
This library has useful tools for when you can't be certain of some things at compile time, such as types, methods, etc. While .NET reflection is immensely powerful, prior to .NET 7, it's not very quick. To address this, this library offers the following extension methods which will emit IL, generate delegates, and cache them for expedited use of Reflection:
ConstructorInfo.FastInvoke: call a constructor only known at runtime quicklyMethodInfo.FastInvoke: call a method only known at runtime quicklyPropertyInfo.FastGetValue: get the value of a property only known at runtime quicklyPropertyInfo.FastSetValue: set the value of a property only known at runtime quicklyType.FastDefault: get the default value of a type only known at runtime quicklyType.GetImplementationEvents: searches for the events of a type, including interfaces and interface inheritanceType.GetImplementationMethods: searches for the methods of a type, including interfaces and interface inheritanceType.GetImplementationProperties: searches for the properties of a type, including interfaces and interface inheritance
FastGetValue and FastSetValue simply call the built-in methods, which are optimized from .NET 7 on.
This library also offers FastComparer and FastEqualityComparer, which implement IComparer and IEqualityComparer, respectively, but quickly use the methods of Comparer<>.Default and EqualityComparer<>.Default, respectively, to do their work.
Where the runtime cannot generate code, as under Native AOT and on iOS, these methods, FastComparer and FastEqualityComparer invoke, construct and compare through reflection instead, with the same results, including comparisons which honor a type's own IComparable<T> or IEquatable<T> as the default comparers do; GetImplementationEvents, GetImplementationMethods and GetImplementationProperties are annotated as reflecting over members which trimming may remove.
In addition (pun intended), this library offers GenericAddition, GenericSubtraction, GenericMultiplication, and GenericDivision, which will produce delegates that will perform the respective operations with values of supplied generic type arguments.
Exceptions
This library provides extension methods for dealing with exceptions:
GetFullDetails- creates a representation of an exception and all of its inner exceptions, including exception types, messages, and stack traces, and traversing multiple inner exceptions in the case ofAggregateExceptionandReflectionTypeLoadException
Threading
This library provides classes for use in threading scenarios:
AsyncSynchronizationContext- A SynchronizationContext that uses the Task Parallel Library (TPL) to process callbacks asynchronously
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. 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 is compatible. 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 is compatible. 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. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Ben.Demystifier (>= 0.4.1)
- Microsoft.Extensions.Logging (>= 8.0.1)
- Microsoft.Extensions.ObjectPool (>= 9.0.4)
- Nito.AsyncEx (>= 5.1.2)
-
net6.0
- Ben.Demystifier (>= 0.4.1)
- Microsoft.Extensions.Logging (>= 8.0.1)
- Microsoft.Extensions.ObjectPool (>= 9.0.4)
- Nito.AsyncEx (>= 5.1.2)
- System.Text.Json (>= 8.0.5)
- System.Threading.Tasks.Dataflow (>= 8.0.1)
-
net7.0
- Ben.Demystifier (>= 0.4.1)
- Microsoft.Extensions.Logging (>= 8.0.1)
- Microsoft.Extensions.ObjectPool (>= 9.0.4)
- Nito.AsyncEx (>= 5.1.2)
- System.Text.Json (>= 8.0.5)
- System.Threading.Tasks.Dataflow (>= 8.0.1)
-
net8.0
- Ben.Demystifier (>= 0.4.1)
- Microsoft.Extensions.Logging (>= 8.0.1)
- Microsoft.Extensions.ObjectPool (>= 9.0.4)
- Nito.AsyncEx (>= 5.1.2)
-
net9.0
- Ben.Demystifier (>= 0.4.1)
- Microsoft.Extensions.Logging (>= 8.0.1)
- Microsoft.Extensions.ObjectPool (>= 9.0.4)
- Nito.AsyncEx (>= 5.1.2)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on Epiforge.Extensions.Components:
| Package | Downloads |
|---|---|
|
Epiforge.Extensions.Expressions
This package assists in operating with expressions. |
|
|
Epiforge.Extensions.Collections
This package assists in operating with collections. |
|
|
Epiforge.Extensions.Platforms.Windows
This package assists in Windows-platform specific operations. |
|
|
Epiforge.Extensions.Frameworks.WPF
This package assists in developing WPF-based applications. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.4.0 | 222 | 10/1/2026 |
| 4.3.1 | 143 | 9/30/2026 |
| 4.3.0 | 512 | 9/9/2026 |
| 4.2.0 | 181 | 9/2/2026 |
| 4.1.1 | 213 | 8/30/2026 |
| 4.1.0 | 159 | 8/29/2026 |
| 4.0.0 | 255 | 8/27/2026 |
| 3.1.0 | 407 | 5/6/2026 |
| 3.0.0 | 303 | 4/14/2026 |
| 2.0.1 | 408 | 12/24/2025 |
| 2.0.0 | 799 | 4/17/2025 |
| 1.7.0 | 369 | 12/30/2023 |
| 1.6.0 | 331 | 12/28/2023 |
| 1.5.0 | 501 | 8/18/2023 |
| 1.4.0 | 1,079 | 8/11/2023 |
| 1.3.2 | 374 | 8/10/2023 |
| 1.3.1 | 280 | 8/10/2023 |
| 1.3.0 | 312 | 7/20/2023 |
| 1.2.0 | 327 | 7/3/2023 |
| 1.1.1 | 327 | 6/25/2023 |
FastInvoker, the FastInvoke and FastDefault extensions, FastComparer and FastEqualityComparer now work where the runtime cannot generate code, as under Native AOT and on iOS: there they invoke and compare through reflection rather than through generated methods, with the same results, including comparisons which honor a type's own IComparable<T> or IEquatable<T> as the default comparers do, and exceptions which arrive unwrapped.
The package is marked as compatible with ahead-of-time compilation, and the members which need generated code or reflect over what trimming may remove now say so: ExceptionExtensions.GetFullDetails, ReflectionExtensions.GetImplementationEvents, GetImplementationMethods and GetImplementationProperties, DynamicPropertyChangeNotifier, DynamicDisposable, DynamicAsyncDisposable and DynamicSyncDisposable.
IsDisposed on the disposable base classes now reads with acquire semantics, so a thread waiting on another thread's disposal sees it; before, a loop polling IsDisposed could be compiled to read the field once and never finish, as it did on .NET 10 on Apple Silicon and on Linux.
Without dynamic code, the invokers and comparers now cast their instance and arguments as the generated ones do, so they accept, convert and refuse the same values with the same exceptions: null for a value-type parameter throws NullReferenceException rather than passing the type's default, a value which would need widening, such as a short for an int, throws InvalidCastException rather than being widened, and an instance or argument of the wrong type throws InvalidCastException or NullReferenceException rather than ArgumentException or TargetException.
FastInvoke now refuses the wrong number of arguments with the ArgumentException FastInvoker throws, where before too few threw IndexOutOfRangeException and too many were ignored; a null argument list still means none. A member which takes or returns a reference, a pointer or a by-reference-like value now throws NotSupportedException when invoked, and an open generic member or an abstract class's constructor InvalidOperationException, where before they threw InvalidProgramException or returned null. FastDefault throws ArgumentException for void, by-reference-like and open generic types, where before it threw ArgumentException, BadImageFormatException or InvalidProgramException.
FastEqualityComparer hashes null as zero for a value type without its own IEquatable<T>, Nullable<T> included, as it already held null equal to null. On .NET 6, FastGetValue and FastSetValue call PropertyInfo.GetValue and SetValue as they do on .NET 7 and later, so null set to a value-type property gives it the type's default there too.