Source only package that exposes newer .NET and C# features to older runtimes.
The package targets netstandard2.0
and is designed to support the following runtimes.
net461
, net462
, net47
, net471
, net472
, net48
, net481
netcoreapp2.0
, netcoreapp2.1
, netcoreapp3.0
, netcoreapp3.1
net5.0
, net6.0
, net7.0
, net8.0
, net9.0
API count: 367
See Milestones for release notes.
Some polyfills are implemented in a way that will not have the equivalent performance to the actual implementations.
For example the polyfill for StringBuilder.Append(ReadOnlySpan<char>)
on netcore2 is:
public StringBuilder Append(ReadOnlySpan<char> value)
=> target.Append(value.ToString());
Which will result in a string allocation.
As Polyfill is implemented as a source only nuget, the implementation for each polyfill is compiled into the IL of the resulting assembly. As a side-effect that implementation will continue to be used even if that assembly is executed in a runtime that has a more efficient implementation available.
As a result, in the context of a project producing nuget package, that project should target all frameworks from the lowest TargetFramework up to and including the current framework. This way the most performant implementation will be used for each runtime. Take the following examples:
https://nuget.org/packages/Polyfill/
This project uses features from the current stable SDK and C# language. As such consuming projects should target those:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<LangVersion>latest</LangVersion>
{
"sdk": {
"version": "8.0.301",
"rollForward": "latestFeature"
}
}
The default type visibility for all polyfills is internal
. This means it can be consumed in multiple projects and types will not conflict.
If Polyfill is being consumed in a solution that produce an app, then it is recommended to use the Polyfill nuget only in the root "app project" and enable PolyPublic
.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PolyPublic>true</PolyPublic>
Then all consuming projects, like tests, will not need to use the Polyfill nuget.
If Polyfill is being consumed in a solution that produce a library (and usually a nuget), then the Polyfill nuget can be added to all projects.
If, however, InternalsVisibleTo
is being used to expose APIs (for example to test projects), then the Polyfill nuget should be added only to the root library project.
Reference: Module Initializers
static bool InitCalled;
[Test]
public void ModuleInitTest() =>
Assert.True(InitCalled);
[ModuleInitializer]
public static void ModuleInit() =>
InitCalled = true;
Reference: init (C# Reference)
class InitSample
{
public int Member { get; init; }
}
Reference: Nullable reference types
Reference: C# required modifier
public class Person
{
public Person()
{
}
[SetsRequiredMembers]
public Person(string name) =>
Name = name;
public required string Name { get; init; }
}
Indicates that compiler support for a particular feature is required for the location where this attribute is applied.
Can be used to make types compatible with collection expressions
Indicates that the specified method parameter expects a constant.
Reference: SkipLocalsInitAttribute
the SkipLocalsInit attribute prevents the compiler from setting the .locals init flag when emitting to metadata. The SkipLocalsInit attribute is a single-use attribute and can be applied to a method, a property, a class, a struct, an interface, or a module, but not to an assembly. SkipLocalsInit is an alias for SkipLocalsInitAttribute.
class SkipLocalsInitSample
{
[SkipLocalsInit]
static void ReadUninitializedMemory()
{
Span<int> numbers = stackalloc int[120];
for (var i = 0; i < 120; i++)
{
Console.WriteLine(numbers[i]);
}
}
}
Reference: Indices and ranges
If consuming in a project that targets net461 or net462, a reference to System.ValueTuple is required. See References: System.ValueTuple.
[TestFixture]
class IndexRangeSample
{
[Test]
public void Range()
{
var substring = "value"[2..];
Assert.AreEqual("lue", substring);
}
[Test]
public void Index()
{
var ch = "value"[^2];
Assert.AreEqual('u', ch);
}
[Test]
public void ArrayIndex()
{
var array = new[]
{
"value1",
"value2"
};
var value = array[^2];
Assert.AreEqual("value1", value);
}
}
C# introduces a new attribute, System.Runtime.CompilerServices.OverloadResolutionPriority, that can be used by API authors to adjust the relative priority of overloads within a single type as a means of steering API consumers to use specific APIs, even if those APIs would normally be considered ambiguous or otherwise not be chosen by C#'s overload resolution rules. This helps framework and library authors guide API usage as they APIs as they develop new and better patterns.
The OverloadResolutionPriorityAttribute can be used in conjunction with the ObsoleteAttribute. A library author may mark properties, methods, types and other programming elements as obsolete, while leaving them in place for backwards compatibility. Using programming elements marked with the ObsoleteAttribute will result in compiler warnings or errors. However, the type or member is still visible to overload resolution and may be selected over a better overload or cause an ambiguity failure. The OverloadResolutionPriorityAttribute lets library authors fix these problems by lowering the priority of obsolete members when there are better alternatives.
[TestFixture]
public class OverloadResolutionPriorityAttributeTests
{
[Test]
public void Run()
{
int[] arr = [1, 2, 3];
//Prints "Span" because resolution priority is higher
Method(arr);
}
[OverloadResolutionPriority(2)]
static void Method(ReadOnlySpan<int> list) =>
Console.WriteLine("Span");
[OverloadResolutionPriority(1)]
static void Method(int[] list) =>
Console.WriteLine("Array");
}
Reference: Low Level Struct Improvements
using System.Diagnostics.CodeAnalysis;
struct UnscopedRefUsage
{
int field;
[UnscopedRef] ref int Prop1 => ref field;
}
Reference: CallerArgumentExpression
static class FileUtil
{
public static void FileExists(string path, [CallerArgumentExpression("path")] string argumentName = "")
{
if (!File.Exists(path))
{
throw new ArgumentException($"File not found. Path: {path}", argumentName);
}
}
}
static class FileUtilUsage
{
public static string[] Method(string path)
{
FileUtil.FileExists(path);
return File.ReadAllLines(path);
}
}
References: String Interpolation in C# 10 and .NET 6, Write a custom string interpolation handler
Reference: .NET 7 - The StringSyntaxAttribute
Reference: Prepare .NET libraries for trimming
Reference: Platform compatibility analyzer
Reference: C# – Hide a method from the stack trace
Reference: Improvements in native code interop in .NET 5.0
The class Polyfill
includes the following extension methods:
[!IMPORTANT] The methods using
AppendInterpolatedStringHandler
parameter are not extensions because the compiler prefers to use the overload withstring
parameter instead.
Boolean TryFormat(Span<Char>, Int32&)
referenceBoolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceCancellationTokenRegistration Register(Action<Object,CancellationToken>, Object)
reference-system-object))CancellationTokenRegistration UnsafeRegister(Action<Object>, Object)
reference-system-object))CancellationTokenRegistration UnsafeRegister(Action<Object,CancellationToken>, Object)
reference-system-object))Task CancelAsync()
referenceTValue GetOrAdd<TKey, TValue, TArg>(TKey, Func<TKey,TArg,TValue>, TArg)
reference-0))Boolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceDateTime AddMicroseconds(Double)
referenceInt32 Microsecond()
referenceInt32 Nanosecond()
referenceBoolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceDateTimeOffset AddMicroseconds(Double)
referenceInt32 Microsecond()
referenceInt32 Nanosecond()
referenceBoolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceBoolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceBoolean Remove<TKey, TValue>(TKey, TValue&)
referenceBoolean TryAdd<TKey, TValue>(TKey, TValue)
referenceBoolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceBoolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>)
reference-system-int32@-system-readonlyspan((system-char))))Boolean TryGetValue<T>(T, T&)
referenceTask<Byte[]> GetByteArrayAsync(String, CancellationToken)
referenceTask<Byte[]> GetByteArrayAsync(Uri, CancellationToken)
referenceTask<Stream> GetStreamAsync(String, CancellationToken)
referenceTask<Stream> GetStreamAsync(Uri, CancellationToken)
referenceTask<String> GetStringAsync(String, CancellationToken)
referenceTask<String> GetStringAsync(Uri, CancellationToken)
referenceTask<Byte[]> ReadAsByteArrayAsync(CancellationToken)
referenceTask<Stream> ReadAsStreamAsync(CancellationToken)
referenceTask<String> ReadAsStringAsync(CancellationToken)
referenceCollections.ObjectModel.ReadOnlyDictionary<TKey,TValue> AsReadOnly<TKey, TValue>()
reference))IEnumerable<ValueTuple<TFirst,TSecond,TThird>> Zip<TFirst, TSecond, TThird>(IEnumerable<TSecond>, IEnumerable<TThird>)
reference-system-collections-generic-ienumerable((-1))-system-collections-generic-ienumerable((-2))))IEnumerable<ValueTuple<TFirst,TSecond>> Zip<TFirst, TSecond>(IEnumerable<TSecond>)
reference-system-collections-generic-ienumerable((-1))))IEnumerable<KeyValuePair<TKey,TAccumulate>> AggregateBy<TSource, TKey, TAccumulate>(Func<TSource,TKey>, TAccumulate, Func<TAccumulate,TSource,TAccumulate>, IEqualityComparer<TKey>)
reference-system-func((-0-1))-system-func((-1-2))-system-func((-2-0-2))-system-collections-generic-iequalitycomparer((-1))))IEnumerable<KeyValuePair<TKey,TAccumulate>> AggregateBy<TSource, TKey, TAccumulate>(Func<TSource,TKey>, Func<TKey,TAccumulate>, Func<TAccumulate,TSource,TAccumulate>, IEqualityComparer<TKey>)
reference-system-func((-0-1))-2-system-func((-2-0-2))-system-collections-generic-iequalitycomparer((-1))))IEnumerable<TSource> Append<TSource>(TSource)
referenceIEnumerable<TSource[]> Chunk<TSource>(Int32)
referenceIEnumerable<KeyValuePair<TKey,Int32>> CountBy<TSource, TKey>(Func<TSource,TKey>, IEqualityComparer<TKey>)
referenceIEnumerable<TSource> DistinctBy<TSource, TKey>(Func<TSource,TKey>)
reference-system-func((-0-1))))IEnumerable<TSource> DistinctBy<TSource, TKey>(Func<TSource,TKey>, IEqualityComparer<TKey>)
reference-system-func((-0-1))-system-collections-generic-iequalitycomparer((-1))))TSource ElementAt<TSource>(Index)
reference-system-index))TSource ElementAtOrDefault<TSource>(Index)
reference-system-index))IEnumerable<TSource> Except<TSource>(TSource)
reference-system-collections-generic-ienumerable((-0))))IEnumerable<TSource> Except<TSource>(TSource, IEqualityComparer<TSource>)
reference-system-collections-generic-ienumerable((-0))-system-collections-generic-iequalitycomparer((-0))))IEnumerable<TSource> Except<TSource>(IEqualityComparer<TSource>, TSource[])
reference-system-collections-generic-ienumerable((-0))-system-collections-generic-iequalitycomparer((-0))))IEnumerable<TSource> ExceptBy<TSource, TKey>(IEnumerable<TKey>, Func<TSource,TKey>)
reference-system-collections-generic-ienumerable((-1))-system-func((-0-1))))IEnumerable<TSource> ExceptBy<TSource, TKey>(IEnumerable<TKey>, Func<TSource,TKey>, IEqualityComparer<TKey>)
reference-system-collections-generic-ienumerable((-1))-system-func((-0-1))-system-collections-generic-iequalitycomparer((-1))))TSource FirstOrDefault<TSource>(Func<TSource,Boolean>, TSource)
reference-system-func((-0-system-boolean))-0))TSource FirstOrDefault<TSource>(TSource)
reference-0))IEnumerable<ValueTuple<Int32,TSource>> Index<TSource>()
reference))TSource LastOrDefault<TSource>(TSource)
reference-0))TSource LastOrDefault<TSource>(Func<TSource,Boolean>, TSource)
reference-system-func((-0-system-boolean))-0))TSource Max<TSource>(IComparer<TSource>)
reference-system-collections-generic-icomparer((-0))))TSource MaxBy<TSource, TKey>(Func<TSource,TKey>)
reference-system-func((-0-1))))TSource MaxBy<TSource, TKey>(Func<TSource,TKey>, IComparer<TKey>)
reference-system-func((-0-1))-system-collections-generic-icomparer((-1))))TSource Min<TSource>(IComparer<TSource>)
reference-system-collections-generic-icomparer((-0))))TSource MinBy<TSource, TKey>(Func<TSource,TKey>)
reference-system-func((-0-1))))TSource MinBy<TSource, TKey>(Func<TSource,TKey>, IComparer<TKey>)
reference-system-func((-0-1))-system-collections-generic-icomparer((-1))))TSource SingleOrDefault<TSource>(Func<TSource,Boolean>, TSource)
reference-system-func((-0-system-boolean))-0))TSource SingleOrDefault<TSource>(TSource)
reference-0))IEnumerable<TSource> SkipLast<TSource>(Int32)
referenceIEnumerable<TSource> Take<TSource>(Range)
reference-system-range))IEnumerable<TSource> TakeLast<TSource>(Int32)
referenceHashSet<TSource> ToHashSet<TSource>(IEqualityComparer<TSource>)
reference-system-collections-generic-iequalitycomparer((-0))))Boolean TryGetNonEnumeratedCount<TSource>(Int32&)
referenceCollections.ObjectModel.ReadOnlyCollection<T> AsReadOnly<T>()
reference))Boolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceBoolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceBoolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceTValue GetValueOrDefault<TKey, TValue>(TKey)
referenceTValue GetValueOrDefault<TKey, TValue>(TKey, TValue)
reference-0-1))void Deconstruct<TKey, TValue>(TKey&, TValue&)
referencevoid AddRange<T>(ReadOnlySpan<T>)
referencevoid CopyTo<T>(Span<T>)
referencevoid InsertRange<T>(Int32, ReadOnlySpan<T>)
referenceTask WaitForExitAsync(CancellationToken)
referencevoid NextBytes(Span<Byte>)
reference))void Shuffle<T>(T[])
reference))void Shuffle<T>(Span<T>)
reference))Boolean EndsWith(String, StringComparison)
reference-system-readonlyspan((-0))))SpanLineEnumerator EnumerateLines()
reference))Boolean SequenceEqual(String)
reference-system-readonlyspan((-0))))Boolean StartsWith(String, StringComparison)
reference-system-readonlyspan((-0))))Boolean Contains<T>(T) where T : IEquatable<T>
reference-0))Polyfills.Polyfill/SpanSplitEnumerator<T> Split<T>(T) where T : IEquatable<T>
reference-0))Polyfills.Polyfill/SpanSplitEnumerator<T> Split<T>(ReadOnlySpan<T>) where T : IEquatable<T>
reference-system-readonlyspan((-0))))Polyfills.Polyfill/SpanSplitEnumerator<T> SplitAny<T>(ReadOnlySpan<T>) where T : IEquatable<T>
reference-system-readonlyspan((-0))))Polyfills.Polyfill/SpanSplitEnumerator<T> SplitAny<T>(Buffers.SearchValues<T>) where T : IEquatable<T>
reference-system-buffers-searchvalues((-0))))Reflection.NullabilityState GetNullability()
Reflection.NullabilityInfo GetNullabilityInfo()
Boolean IsNullable()
Reflection.NullabilityState GetNullability()
Reflection.NullabilityInfo GetNullabilityInfo()
Boolean IsNullable()
Reflection.NullabilityState GetNullability()
Reflection.NullabilityInfo GetNullabilityInfo()
Boolean HasSameMetadataDefinitionAs(Reflection.MemberInfo)
referenceBoolean IsNullable()
Reflection.NullabilityState GetNullability()
Reflection.NullabilityInfo GetNullabilityInfo()
Boolean IsNullable()
Reflection.NullabilityState GetNullability()
Reflection.NullabilityInfo GetNullabilityInfo()
Boolean IsNullable()
ValueMatchEnumerator EnumerateMatches(ReadOnlySpan<Char>)
reference))ValueMatchEnumerator EnumerateMatches(ReadOnlySpan<Char>, Int32)
reference-system-int32))Boolean IsMatch(ReadOnlySpan<Char>, Int32)
reference-system-int32))Boolean IsMatch(ReadOnlySpan<Char>)
reference))Boolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceBoolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceTKey GetKeyAtIndex<TKey, TValue>(Int32)
referenceTValue GetValueAtIndex<TKey, TValue>(Int32)
referenceBoolean EndsWith(String)
reference-system-readonlyspan((-0))))SpanLineEnumerator EnumerateLines()
reference))Boolean SequenceEqual(String)
reference-system-readonlyspan((-0))))Boolean StartsWith(String)
reference-system-readonlyspan((-0))))Span<Char> TrimEnd()
reference))Span<Char> TrimStart()
reference))Boolean Contains<T>(T) where T : IEquatable<T>
reference-0))Task CopyToAsync(Stream, CancellationToken)
referenceValueTask DisposeAsync()
referenceValueTask<Int32> ReadAsync(Memory<Byte>, CancellationToken)
reference-system-threading-cancellationtoken))ValueTask WriteAsync(ReadOnlyMemory<Byte>, CancellationToken)
reference-system-threading-cancellationtoken))Boolean Contains(String, StringComparison)
referenceBoolean Contains(Char)
referencevoid CopyTo(Span<Char>)
referenceBoolean EndsWith(Char)
referenceInt32 GetHashCode(StringComparison)
referenceString[] Split(Char, StringSplitOptions)
referenceString[] Split(Char, Int32, StringSplitOptions)
referenceBoolean StartsWith(Char)
referenceBoolean TryCopyTo(Span<Char>)
referenceStringBuilder Append(ReadOnlySpan<Char>)
reference))StringBuilder Append(StringBuilder, AppendInterpolatedStringHandler&)
referenceStringBuilder Append(StringBuilder, IFormatProvider, AppendInterpolatedStringHandler&)
referenceStringBuilder Append(StringBuilder, StringBuilder/AppendInterpolatedStringHandler&)
referenceStringBuilder Append(StringBuilder, IFormatProvider, StringBuilder/AppendInterpolatedStringHandler&)
referenceStringBuilder AppendJoin(String, String[])
reference)StringBuilder AppendJoin(String, Object[])
reference)StringBuilder AppendJoin(Char, String[])
reference)StringBuilder AppendJoin(Char, Object[])
reference)StringBuilder AppendJoin<T>(Char, T[])
reference))StringBuilder AppendJoin<T>(String, T[])
reference))StringBuilder AppendLine(StringBuilder, AppendInterpolatedStringHandler&)
referenceStringBuilder AppendLine(StringBuilder, IFormatProvider, AppendInterpolatedStringHandler&)
referenceStringBuilder AppendLine(StringBuilder, StringBuilder/AppendInterpolatedStringHandler&)
referenceStringBuilder AppendLine(StringBuilder, IFormatProvider, StringBuilder/AppendInterpolatedStringHandler&)
referencevoid CopyTo(Int32, Span<Char>, Int32)
reference-system-int32))Boolean Equals(ReadOnlySpan<Char>)
reference))Polyfills.Polyfill/ChunkEnumerator GetChunks()
referenceStringBuilder Replace(ReadOnlySpan<Char>, ReadOnlySpan<Char>)
reference-system-readonlyspan((system-char))))StringBuilder Replace(ReadOnlySpan<Char>, ReadOnlySpan<Char>, Int32, Int32)
referenceTask WaitAsync(CancellationToken)
referenceTask WaitAsync(TimeSpan)
referenceTask WaitAsync(TimeSpan, CancellationToken)
referenceTask<TResult> WaitAsync<TResult>(CancellationToken)
referenceTask<TResult> WaitAsync<TResult>(TimeSpan)
referenceTask<TResult> WaitAsync<TResult>(TimeSpan, CancellationToken)
referencevoid SetCanceled<T>(CancellationToken)
referenceValueTask<Int32> ReadAsync(Memory<Char>, CancellationToken)
reference-system-threading-cancellationtoken))Task<String> ReadLineAsync(CancellationToken)
referenceTask<String> ReadToEndAsync(CancellationToken)
referenceTask FlushAsync(CancellationToken)
referencevoid Write(StringBuilder)
referencevoid Write(ReadOnlySpan<Char>)
reference))Task WriteAsync(StringBuilder, CancellationToken)
reference-system-threading-cancellationtoken))ValueTask WriteAsync(ReadOnlyMemory<Char>, CancellationToken)
reference-system-threading-cancellationtoken))void WriteLine(ReadOnlySpan<Char>)
reference))ValueTask WriteLineAsync(ReadOnlyMemory<Char>, CancellationToken)
reference-system-threading-cancellationtoken))Boolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceInt32 Microseconds()
referenceInt32 Nanoseconds()
referenceBoolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
reference-system-int32@-system-readonlyspan((system-char))-system-iformatprovider))Reflection.MethodInfo GetMethod(String, Int32, Reflection.BindingFlags, Type[])
reference)Boolean IsAssignableFrom<T>()
Boolean IsAssignableTo<T>()
Boolean IsAssignableTo(Type)
referenceBoolean IsGenericMethodParameter()
referenceBoolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceBoolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceBoolean TryFormat(Span<Char>, Int32&, ReadOnlySpan<Char>, IFormatProvider)
referenceTask SaveAsync(Xml.XmlWriter, CancellationToken)
referenceTask SaveAsync(Stream, Xml.Linq.SaveOptions, CancellationToken)
referenceTask SaveAsync(TextWriter, Xml.Linq.SaveOptions, CancellationToken)
referenceString[] GetNames<TEnum>() where TEnum : Enum, ValueType
referenceTEnum[] GetValues<TEnum>() where TEnum : Enum, ValueType
referenceBoolean IsDefined<TEnum>(TEnum) where TEnum : Enum, ValueType
referenceTEnum Parse<TEnum>(String) where TEnum : Enum, ValueType
referenceTEnum Parse<TEnum>(String, Boolean) where TEnum : Enum, ValueType
referenceTEnum Parse<TEnum>(ReadOnlySpan<Char>) where TEnum : Enum, ValueType
reference))TEnum Parse<TEnum>(ReadOnlySpan<Char>, Boolean) where TEnum : Enum, ValueType
reference-system-boolean))Boolean TryParse<TEnum>(ReadOnlySpan<Char>, TEnum&) where TEnum : Enum, ValueType
reference-0@))Boolean TryParse<TEnum>(ReadOnlySpan<Char>, Boolean, TEnum&) where TEnum : Enum, ValueType
reference-system-boolean-0@))ValueMatchEnumerator EnumerateMatches(ReadOnlySpan<Char>, String)
reference-system-string))ValueMatchEnumerator EnumerateMatches(ReadOnlySpan<Char>, String, RegexOptions, TimeSpan)
reference-system-string-system-text-regularexpressions-regexoptions-system-timespan))ValueMatchEnumerator EnumerateMatches(ReadOnlySpan<Char>, String, RegexOptions)
reference-system-string-system-text-regularexpressions-regexoptions))Regex/ValueMatchEnumerator EnumerateMatches(ReadOnlySpan<Char>, String)
reference-system-string))Regex/ValueMatchEnumerator EnumerateMatches(ReadOnlySpan<Char>, String, RegexOptions, TimeSpan)
reference-system-string-system-text-regularexpressions-regexoptions-system-timespan))Regex/ValueMatchEnumerator EnumerateMatches(ReadOnlySpan<Char>, String, RegexOptions)
reference-system-string-system-text-regularexpressions-regexoptions))Boolean IsMatch(ReadOnlySpan<Char>, String, RegexOptions, TimeSpan)
reference-system-string-system-text-regularexpressions-regexoptions-system-timespan))Boolean IsMatch(ReadOnlySpan<Char>, String, RegexOptions)
reference-system-string-system-text-regularexpressions-regexoptions))Boolean IsMatch(ReadOnlySpan<Char>, String)
reference-system-string))String Join(Char, String[])
reference)String Join(Char, Object[])
reference)String Join(Char, String[], Int32, Int32)
reference)String Join<T>(Char, IEnumerable<T>)
reference))Boolean TryParse(String, IFormatProvider, Byte&)
referenceBoolean TryParse(ReadOnlySpan<Byte>, IFormatProvider, Byte&)
reference-system-iformatprovider-system-byte@))Boolean TryParse(ReadOnlySpan<Char>, Byte&)
reference-system-byte@))Boolean TryParse(ReadOnlySpan<Char>, IFormatProvider, Byte&)
reference-system-iformatprovider-system-byte@))Boolean TryParse(ReadOnlySpan<Byte>, Globalization.NumberStyles, IFormatProvider, Byte&)
reference-system-globalization-numberstyles-system-iformatprovider-system-byte@))Boolean TryParse(ReadOnlySpan<Byte>, Byte&)
reference-system-globalization-numberstyles-system-iformatprovider-system-byte@))Boolean TryParse(ReadOnlySpan<Char>, Globalization.NumberStyles, IFormatProvider, Byte&)
reference-system-globalization-numberstyles-system-iformatprovider-system-byte@))Boolean TryParse(String, IFormatProvider, Guid&)
referenceBoolean TryParse(ReadOnlySpan<Char>, IFormatProvider, Guid&)
reference-system-iformatprovider-system-guid@))Boolean TryParse(ReadOnlySpan<Char>, Guid&)
reference-system-guid@))Boolean TryParse(String, IFormatProvider, DateTime&)
referenceBoolean TryParse(ReadOnlySpan<Char>, IFormatProvider, DateTime&)
reference-system-iformatprovider-system-datetime@))Boolean TryParse(ReadOnlySpan<Char>, DateTime&)
reference-system-datetime@))Boolean TryParse(ReadOnlySpan<Char>, IFormatProvider, Globalization.DateTimeStyles, DateTime&)
reference-system-iformatprovider-system-globalization-datetimestyles-system-datetime@))Boolean TryParseExact(ReadOnlySpan<Char>, String, IFormatProvider, Globalization.DateTimeStyles, DateTime&)
reference-system-readonlyspan((system-char))-system-iformatprovider-system-globalization-datetimestyles-system-datetime@))Boolean TryParseExact(ReadOnlySpan<Char>, ReadOnlySpan<Char>, IFormatProvider, Globalization.DateTimeStyles, DateTime&)
reference-system-readonlyspan((system-char))-system-iformatprovider-system-globalization-datetimestyles-system-datetime@))Boolean TryParse(String, IFormatProvider, DateTimeOffset&)
referenceBoolean TryParse(ReadOnlySpan<Char>, IFormatProvider, DateTimeOffset&)
reference-system-iformatprovider-system-datetimeoffset@))Boolean TryParse(ReadOnlySpan<Char>, DateTimeOffset&)
reference-system-datetimeoffset@))Boolean TryParse(ReadOnlySpan<Char>, IFormatProvider, Globalization.DateTimeStyles, DateTimeOffset&)
reference-system-iformatprovider-system-globalization-datetimestyles-system-datetimeoffset@))Boolean TryParseExact(ReadOnlySpan<Char>, String, IFormatProvider, Globalization.DateTimeStyles, DateTimeOffset&)
reference-system-readonlyspan((system-char))-system-iformatprovider-system-globalization-datetimestyles-system-datetimeoffset@))Boolean TryParseExact(ReadOnlySpan<Char>, ReadOnlySpan<Char>, IFormatProvider, Globalization.DateTimeStyles, DateTimeOffset&)
reference-system-readonlyspan((system-char))-system-iformatprovider-system-globalization-datetimestyles-system-datetimeoffset@))Boolean TryParse(String, IFormatProvider, Double&)
referenceBoolean TryParse(ReadOnlySpan<Byte>, IFormatProvider, Double&)
reference-system-iformatprovider-system-double@))Boolean TryParse(ReadOnlySpan<Char>, Double&)
reference-system-double@))Boolean TryParse(ReadOnlySpan<Char>, IFormatProvider, Double&)
reference-system-iformatprovider-system-double@))Boolean TryParse(ReadOnlySpan<Byte>, Globalization.NumberStyles, IFormatProvider, Double&)
reference-system-globalization-numberstyles-system-iformatprovider-system-double@))Boolean TryParse(ReadOnlySpan<Byte>, Double&)
reference-system-double@))Boolean TryParse(ReadOnlySpan<Char>, Globalization.NumberStyles, IFormatProvider, Double&)
reference-system-globalization-numberstyles-system-iformatprovider-system-double@))Boolean TryParse(String, IFormatProvider, Int32&)
referenceBoolean TryParse(ReadOnlySpan<Byte>, IFormatProvider, Int32&)
reference-system-iformatprovider-system-int32@))Boolean TryParse(ReadOnlySpan<Char>, Int32&)
reference-system-int32@))Boolean TryParse(ReadOnlySpan<Char>, IFormatProvider, Int32&)
reference-system-iformatprovider-system-int32@))Boolean TryParse(ReadOnlySpan<Byte>, Globalization.NumberStyles, IFormatProvider, Int32&)
reference-system-globalization-numberstyles-system-iformatprovider-system-int32@))Boolean TryParse(ReadOnlySpan<Byte>, Int32&)
reference-system-globalization-numberstyles-system-iformatprovider-system-int32@))Boolean TryParse(ReadOnlySpan<Char>, Globalization.NumberStyles, IFormatProvider, Int32&)
reference-system-globalization-numberstyles-system-iformatprovider-system-int32@))Boolean TryParse(String, IFormatProvider, Int32&)
referenceBoolean TryParse(ReadOnlySpan<Byte>, IFormatProvider, Int32&)
reference-system-iformatprovider-system-int64@))Boolean TryParse(ReadOnlySpan<Char>, Int32&)
reference-system-int64@))Boolean TryParse(ReadOnlySpan<Char>, IFormatProvider, Int32&)
reference-system-iformatprovider-system-int64@))Boolean TryParse(ReadOnlySpan<Byte>, Globalization.NumberStyles, IFormatProvider, Int32&)
reference-system-globalization-numberstyles-system-iformatprovider-system-int64@))Boolean TryParse(ReadOnlySpan<Byte>, Int32&)
reference-system-globalization-numberstyles-system-iformatprovider-system-int64@))Boolean TryParse(ReadOnlySpan<Char>, Globalization.NumberStyles, IFormatProvider, Int32&)
reference-system-globalization-numberstyles-system-iformatprovider-system-int64@))Boolean TryParse(String, IFormatProvider, SByte&)
referenceBoolean TryParse(ReadOnlySpan<Byte>, IFormatProvider, SByte&)
reference-system-iformatprovider-system-sbyte@))Boolean TryParse(ReadOnlySpan<Char>, SByte&)
reference-system-sbyte@))Boolean TryParse(ReadOnlySpan<Char>, IFormatProvider, SByte&)
reference-system-iformatprovider-system-sbyte@))Boolean TryParse(ReadOnlySpan<Byte>, Globalization.NumberStyles, IFormatProvider, SByte&)
reference-system-globalization-numberstyles-system-iformatprovider-system-sbyte@))Boolean TryParse(ReadOnlySpan<Byte>, SByte&)
reference-system-globalization-numberstyles-system-iformatprovider-system-sbyte@))Boolean TryParse(ReadOnlySpan<Char>, Globalization.NumberStyles, IFormatProvider, SByte&)
reference-system-globalization-numberstyles-system-iformatprovider-system-sbyte@))Boolean TryParse(String, IFormatProvider, Int16&)
referenceBoolean TryParse(ReadOnlySpan<Byte>, IFormatProvider, Int16&)
reference-system-iformatprovider-system-int16@))Boolean TryParse(ReadOnlySpan<Char>, Int16&)
reference-system-int16@))Boolean TryParse(ReadOnlySpan<Char>, IFormatProvider, Int16&)
reference-system-iformatprovider-system-int16@))Boolean TryParse(ReadOnlySpan<Byte>, Globalization.NumberStyles, IFormatProvider, Int16&)
reference-system-globalization-numberstyles-system-iformatprovider-system-int16@))Boolean TryParse(ReadOnlySpan<Byte>, Int16&)
reference-system-globalization-numberstyles-system-iformatprovider-system-int16@))Boolean TryParse(ReadOnlySpan<Char>, Globalization.NumberStyles, IFormatProvider, Int16&)
reference-system-globalization-numberstyles-system-iformatprovider-system-int16@))Boolean TryParse(String, IFormatProvider, UInt32&)
referenceBoolean TryParse(ReadOnlySpan<Byte>, IFormatProvider, UInt32&)
reference-system-iformatprovider-system-uint32@))Boolean TryParse(ReadOnlySpan<Char>, UInt32&)
reference-system-uint32@))Boolean TryParse(ReadOnlySpan<Char>, IFormatProvider, UInt32&)
reference-system-iformatprovider-system-uint32@))Boolean TryParse(ReadOnlySpan<Byte>, Globalization.NumberStyles, IFormatProvider, UInt32&)
reference-system-globalization-numberstyles-system-iformatprovider-system-uint32@))Boolean TryParse(ReadOnlySpan<Byte>, UInt32&)
reference-system-globalization-numberstyles-system-iformatprovider-system-uint32@))Boolean TryParse(ReadOnlySpan<Char>, Globalization.NumberStyles, IFormatProvider, UInt32&)
reference-system-globalization-numberstyles-system-iformatprovider-system-uint32@))Boolean TryParse(String, IFormatProvider, UInt64&)
referenceBoolean TryParse(ReadOnlySpan<Byte>, IFormatProvider, UInt64&)
reference-system-iformatprovider-system-uint64@))Boolean TryParse(ReadOnlySpan<Char>, UInt64&)
reference-system-uint64@))Boolean TryParse(ReadOnlySpan<Char>, IFormatProvider, UInt64&)
reference-system-iformatprovider-system-uint64@))Boolean TryParse(ReadOnlySpan<Byte>, Globalization.NumberStyles, IFormatProvider, UInt64&)
reference-system-globalization-numberstyles-system-iformatprovider-system-uint64@))Boolean TryParse(ReadOnlySpan<Byte>, UInt64&)
reference-system-globalization-numberstyles-system-iformatprovider-system-uint64@))Boolean TryParse(ReadOnlySpan<Char>, Globalization.NumberStyles, IFormatProvider, UInt64&)
reference-system-globalization-numberstyles-system-iformatprovider-system-uint64@))Boolean TryParse(String, IFormatProvider, UInt16&)
referenceBoolean TryParse(ReadOnlySpan<Byte>, IFormatProvider, UInt16&)
reference-system-iformatprovider-system-uint16@))Boolean TryParse(ReadOnlySpan<Char>, UInt16&)
reference-system-uint16@))Boolean TryParse(ReadOnlySpan<Char>, IFormatProvider, UInt16&)
reference-system-iformatprovider-system-uint16@))Boolean TryParse(ReadOnlySpan<Byte>, Globalization.NumberStyles, IFormatProvider, UInt16&)
reference-system-globalization-numberstyles-system-iformatprovider-system-uint16@))Boolean TryParse(ReadOnlySpan<Byte>, UInt16&)
reference-system-globalization-numberstyles-system-iformatprovider-system-uint16@))Boolean TryParse(ReadOnlySpan<Char>, Globalization.NumberStyles, IFormatProvider, UInt16&)
reference-system-globalization-numberstyles-system-iformatprovider-system-uint16@))void DirectoryExists(String)
void FileExists(String)
void NotEmpty(String)
void NotEmpty<T>(ReadOnlySpan<T>)
void NotEmpty<T>(Span<T>)
void NotEmpty<T>(Nullable<Memory<T>>)
void NotEmpty<T>(Memory<T>)
void NotEmpty<T>(Nullable<ReadOnlyMemory<T>>)
void NotEmpty<T>(ReadOnlyMemory<T>)
void NotEmpty<T>(T) where T : Collections.IEnumerable
T NotNull<T>(T)
String NotNull(String)
String NotNullOrEmpty(String)
T NotNullOrEmpty<T>(T) where T : Collections.IEnumerable
Memory<Char> NotNullOrEmpty(Nullable<Memory<Char>>)
ReadOnlyMemory<Char> NotNullOrEmpty(Nullable<ReadOnlyMemory<Char>>)
String NotNullOrWhiteSpace(String)
Memory<Char> NotNullOrWhiteSpace(Nullable<Memory<Char>>)
ReadOnlyMemory<Char> NotNullOrWhiteSpace(Nullable<ReadOnlyMemory<Char>>)
void NotWhiteSpace(String)
void NotWhiteSpace(ReadOnlySpan<Char>)
void NotWhiteSpace(Nullable<Memory<Char>>)
void NotWhiteSpace(Nullable<ReadOnlyMemory<Char>>)
void NotWhiteSpace(Span<Char>)
void Enter()
Lock/Scope EnterScope()
void Exit()
Boolean get_IsHeldByCurrentThread()
Boolean TryEnter()
Boolean TryEnter(TimeSpan)
Boolean TryEnter(Int32)
If any of the below reference are not included, the related polyfills will be disabled.
If consuming in a project that targets net461
or net462
, a reference to System.ValueTuple nuget is required.
<PackageReference Include="System.ValueTuple"
Version="4.5.0"
Condition="$(TargetFramework.StartsWith('net46'))" />
If using Span APIs and consuming in a project that targets netstandard
, netframework
, or netcoreapp2*
, a reference to System.Memory nuget is required.
<PackageReference Include="System.Memory"
Version="4.5.5"
Condition="$(TargetFrameworkIdentifier) == '.NETStandard' or
$(TargetFrameworkIdentifier) == '.NETFramework' or
$(TargetFramework.StartsWith('netcoreapp2'))" />
If using ValueTask APIs and consuming in a project that target netframework
, netstandard2
, or netcoreapp2
, a reference to System.Threading.Tasks.Extensions nuget is required.
<PackageReference Include="System.Threading.Tasks.Extensions"
Version="4.5.4"
Condition="$(TargetFramework) == 'netstandard2.0' or
$(TargetFramework) == 'netcoreapp2.0' or
$(TargetFrameworkIdentifier) == '.NETFramework'" />
Given the following class
class NullabilityTarget
{
public string? StringField;
public string?[] ArrayField;
public Dictionary<string, object?> GenericField;
}
[Test]
public void Test()
{
var type = typeof(NullabilityTarget);
var arrayField = type.GetField("ArrayField")!;
var genericField = type.GetField("GenericField")!;
var context = new NullabilityInfoContext();
var arrayInfo = context.Create(arrayField);
Assert.AreEqual(NullabilityState.NotNull, arrayInfo.ReadState);
Assert.AreEqual(NullabilityState.Nullable, arrayInfo.ElementType!.ReadState);
var genericInfo = context.Create(genericField);
Assert.AreEqual(NullabilityState.NotNull, genericInfo.ReadState);
Assert.AreEqual(NullabilityState.NotNull, genericInfo.GenericTypeArguments[0].ReadState);
Assert.AreEqual(NullabilityState.Nullable, genericInfo.GenericTypeArguments[1].ReadState);
}
Enable by adding and MSBuild property PolyNullability
<PropertyGroup>
...
<PolyNullability>true</PolyNullability>
</PropertyGroup>
NullabilityInfoExtensions
provides static and thread safe wrapper around NullabilityInfoContext
. It adds three extension methods to each of ParameterInfo, PropertyInfo, EventInfo, and FieldInfo.
GetNullabilityInfo
: returns the NullabilityInfo
for the target info.GetNullability
: returns the NullabilityState
for the state (NullabilityInfo.ReadState
or NullabilityInfo.WriteState
depending on which has more info) of target info.IsNullable
: given the state (NullabilityInfo.ReadState
or NullabilityInfo.WriteState
depending on which has more info) of the info:
NullabilityState.Nullable
.NullabilityState.NotNull
.NullabilityState.Unknown
.Enable by adding and MSBuild property PolyGuard
<PropertyGroup>
...
<PolyGuard>true</PolyGuard>
</PropertyGroup>
Guard
is designed to be a an alternative to the ArgumentException.ThrowIf*
APIs added in net7.
ArgumentException.ThrowIfNullOrEmpty
referenceArgumentException.ThrowIfNullOrWhiteSpace
referenceArgumentNullException.ThrowIfNull
referenceWith the equivalent Guard APIs:
Guard.NotNullOrEmpty
Guard.NotNullOrWhiteSpace
Guard.NotNull
Polyfills.Guard
provides the following APIs:
void DirectoryExists(String)
void FileExists(String)
void NotEmpty(String)
void NotEmpty<T>(ReadOnlySpan<T>)
void NotEmpty<T>(Span<T>)
void NotEmpty<T>(Nullable<Memory<T>>)
void NotEmpty<T>(Memory<T>)
void NotEmpty<T>(Nullable<ReadOnlyMemory<T>>)
void NotEmpty<T>(ReadOnlyMemory<T>)
void NotEmpty<T>(T) where T : Collections.IEnumerable
T NotNull<T>(T)
String NotNull(String)
String NotNullOrEmpty(String)
T NotNullOrEmpty<T>(T) where T : Collections.IEnumerable
Memory<Char> NotNullOrEmpty(Nullable<Memory<Char>>)
ReadOnlyMemory<Char> NotNullOrEmpty(Nullable<ReadOnlyMemory<Char>>)
String NotNullOrWhiteSpace(String)
Memory<Char> NotNullOrWhiteSpace(Nullable<Memory<Char>>)
ReadOnlyMemory<Char> NotNullOrWhiteSpace(Nullable<ReadOnlyMemory<Char>>)
void NotWhiteSpace(String)
void NotWhiteSpace(ReadOnlySpan<Char>)
void NotWhiteSpace(Nullable<Memory<Char>>)
void NotWhiteSpace(Nullable<ReadOnlyMemory<Char>>)
void NotWhiteSpace(Span<Char>)
https://github.com/Tyrrrz/PolyShim
https://github.com/Sergio0694/PolySharp
https://github.com/theraot/Theraot
PolySharp uses c# source generators. In my opinion a "source-only package" implementation is better because:
The combination of the other 3 packages is not ideal because:
Crack designed by Adrien Coquet from The Noun Project.