Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
</Choose>

<ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning" Version="3.6.128" PrivateAssets="All" />
<PackageReference Include="Nerdbank.GitVersioning" Version="3.6.133" PrivateAssets="All" />
</ItemGroup>

<Choose>
Expand All @@ -39,7 +39,7 @@
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
</ItemGroup>
</When>
</Choose>
Expand Down
4 changes: 4 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ jobs:

# Test solution #

# Run .NET 8 unit tests
- script: dotnet test --no-build -c $(Build.Configuration) -f net8.0 -l "trx;LogFileName=VSTestResults_net8.0.trx"
displayName: Run .NET 8 unit tests

# Run .NET 7 unit tests
- script: dotnet test --no-build -c $(Build.Configuration) -f net7.0 -l "trx;LogFileName=VSTestResults_net7.0.trx"
displayName: Run .NET 7 unit tests
Expand Down
2 changes: 1 addition & 1 deletion build/Community.Toolkit.Common.props
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>11.0</LangVersion>
<LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable>

<!--
Expand Down
1 change: 0 additions & 1 deletion build/Community.Toolkit.Common.targets
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<Project>

<PropertyGroup>
<!-- TODO: Dynamically generate Title if one wasn't set -->
<Title Condition="'$(Title)' == ''">$(Product) Asset</Title>
</PropertyGroup>

Expand Down
2 changes: 1 addition & 1 deletion src/CommunityToolkit.Common/CommunityToolkit.Common.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net8.0</TargetFrameworks>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net8.0</TargetFrameworks>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static ref T DangerousGetValueOrDefaultReference<T>(this ref T? value)
/// <typeparam name="T">The type of the underlying value.</typeparam>
/// <param name="value">The <see cref="Nullable{T}"/>.</param>
/// <returns>A reference to the value of the input <see cref="Nullable{T}"/> instance, or a <see langword="null"/> <typeparamref name="T"/> reference.</returns>
/// <remarks>The returned reference can be tested for <see langword="null"/> using <see cref="Unsafe.IsNullRef{T}(ref T)"/>.</remarks>
/// <remarks>The returned reference can be tested for <see langword="null"/> using <see cref="Unsafe.IsNullRef"/>.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe ref T DangerousGetValueOrNullReference<T>(ref this T? value)
where T : struct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ public static ReadOnlySpan2D<T> AsSpan2D<T>(this ReadOnlySpan<T> span, int offse
public static unsafe int IndexOf<T>(this ReadOnlySpan<T> span, in T value)
{
ref T r0 = ref MemoryMarshal.GetReference(span);
ref T r1 = ref Unsafe.AsRef(value);
ref T r1 = ref Unsafe.AsRef(in value);
IntPtr byteOffset = Unsafe.ByteOffset(ref r0, ref r1);

nint elementOffset = byteOffset / (nint)(uint)sizeof(T);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ public static unsafe void Write<T>(this Stream stream, in T value)
where T : unmanaged
{
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref Unsafe.AsRef(value);
ref T r0 = ref Unsafe.AsRef(in value);
ref byte r1 = ref Unsafe.As<T, byte>(ref r0);
int length = sizeof(T);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static class StringExtensions
public static ref char DangerousGetReference(this string text)
{
#if NET6_0_OR_GREATER
return ref Unsafe.AsRef(text.GetPinnableReference());
return ref Unsafe.AsRef(in text.GetPinnableReference());
#else
return ref MemoryMarshal.GetReference(text.AsSpan());
#endif
Expand All @@ -44,7 +44,7 @@ public static ref char DangerousGetReference(this string text)
public static ref char DangerousGetReferenceAt(this string text, int i)
{
#if NET6_0_OR_GREATER
ref char r0 = ref Unsafe.AsRef(text.GetPinnableReference());
ref char r0 = ref Unsafe.AsRef(in text.GetPinnableReference());
#else
ref char r0 = ref MemoryMarshal.GetReference(text.AsSpan());
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public static void For<TAction>(int start, int end, in TAction action, int minim
{
for (int i = start; i < end; i++)
{
Unsafe.AsRef(action).Invoke(i);
Unsafe.AsRef(in action).Invoke(i);
}

return;
Expand Down Expand Up @@ -225,7 +225,7 @@ public void Invoke(int i)

for (int j = low; j < stop; j++)
{
Unsafe.AsRef(this.action).Invoke(j);
Unsafe.AsRef(in this.action).Invoke(j);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ public static void For2D<TAction>(int top, int bottom, int left, int right, in T
{
for (int x = left; x < right; x++)
{
Unsafe.AsRef(action).Invoke(y, x);
Unsafe.AsRef(in action).Invoke(y, x);
}
}

Expand Down Expand Up @@ -319,7 +319,7 @@ public void Invoke(int i)
{
for (int x = this.startX; x < this.endX; x++)
{
Unsafe.AsRef(this.action).Invoke(y, x);
Unsafe.AsRef(in this.action).Invoke(y, x);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public static void ForEach<TItem, TAction>(ReadOnlyMemory<TItem> memory, in TAct
{
foreach (TItem? item in memory.Span)
{
Unsafe.AsRef(action).Invoke(item);
Unsafe.AsRef(in action).Invoke(item);
}

return;
Expand Down Expand Up @@ -144,7 +144,7 @@ public void Invoke(int i)

while (Unsafe.IsAddressLessThan(ref rStart, ref rEnd))
{
Unsafe.AsRef(this.action).Invoke(in rStart);
Unsafe.AsRef(in this.action).Invoke(in rStart);

rStart = ref Unsafe.Add(ref rStart, 1);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public void Invoke(int i)

while (Unsafe.IsAddressLessThan(ref rStart, ref rEnd))
{
Unsafe.AsRef(this.action).Invoke(in rStart);
Unsafe.AsRef(in this.action).Invoke(in rStart);

rStart = ref Unsafe.Add(ref rStart, 1);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public static void ForEach<TItem, TAction>(Memory<TItem> memory, in TAction acti
{
foreach (ref TItem item in memory.Span)
{
Unsafe.AsRef(action).Invoke(ref item);
Unsafe.AsRef(in action).Invoke(ref item);
}

return;
Expand Down Expand Up @@ -144,7 +144,7 @@ public void Invoke(int i)

while (Unsafe.IsAddressLessThan(ref rStart, ref rEnd))
{
Unsafe.AsRef(this.action).Invoke(ref rStart);
Unsafe.AsRef(in this.action).Invoke(ref rStart);

rStart = ref Unsafe.Add(ref rStart, 1);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public void Invoke(int i)

while (Unsafe.IsAddressLessThan(ref rStart, ref rEnd))
{
Unsafe.AsRef(this.action).Invoke(ref rStart);
Unsafe.AsRef(in this.action).Invoke(ref rStart);

rStart = ref Unsafe.Add(ref rStart, 1);
}
Expand Down
7 changes: 4 additions & 3 deletions src/CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net8.0</TargetFrameworks>
</PropertyGroup>

<PropertyGroup>
Expand All @@ -22,7 +22,7 @@

<!-- .NET Standard 2.0 doesn't have the Span<T> and IAsyncEnumerable<T> types -->
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
Expand Down Expand Up @@ -55,6 +55,7 @@
System.Diagnostics.CodeAnalysis.NotNullAttribute;
System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute;
System.Diagnostics.CodeAnalysis.NotNullWhenAttribute;
System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute;
System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute;
System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute;
System.Runtime.CompilerServices.CallerArgumentExpressionAttribute;
Expand All @@ -65,7 +66,7 @@

<ItemGroup Label="Package">

<!-- Include the custom .targets file to check the source generator (.NET 6 is not needed as it guarantees Roslyn 4.x) -->
<!-- Include the custom .targets file to check the source generator (.NET 6 and 8 are not needed as they guarantee Roslyn 4.x) -->
<None Include="CommunityToolkit.Mvvm.targets" PackagePath="buildTransitive\netstandard2.0" Pack="true" />
<None Include="CommunityToolkit.Mvvm.targets" PackagePath="buildTransitive\netstandard2.1" Pack="true" />
<None Include="CommunityToolkit.Mvvm.targets" PackagePath="build\netstandard2.0" Pack="true" />
Expand Down
11 changes: 11 additions & 0 deletions src/CommunityToolkit.Mvvm/ComponentModel/ObservableRecipient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ public bool IsActive
"If this type is removed by the linker, or if the target recipient was created dynamically and was missed by the source generator, a slower fallback " +
"path using a compiled LINQ expression will be used. This will have more overhead in the first invocation of this method for any given recipient type. " +
"Alternatively, OnActivated() can be manually overwritten, and registration can be done individually for each required message for this recipient.")]
[RequiresDynamicCode(
"When this property is set to true, the OnActivated() method will be invoked, which will register all necessary message handlers for this recipient. " +
"This method requires the generated CommunityToolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions type not to be removed to use the fast path. " +
"If that is present, the method is AOT safe, as the only methods being invoked to register the messages will be the ones produced by the source generator. " +
"If it isn't, this method will need to dynamically create the generic methods to register messages, which might not be available at runtime. " +
"Alternatively, OnActivated() can be manually overwritten, and registration can be done individually for each required message for this recipient.")]
set
{
if (SetProperty(ref this.isActive, value, true))
Expand Down Expand Up @@ -96,6 +102,11 @@ public bool IsActive
"If this type is removed by the linker, or if the target recipient was created dynamically and was missed by the source generator, a slower fallback " +
"path using a compiled LINQ expression will be used. This will have more overhead in the first invocation of this method for any given recipient type. " +
"Alternatively, OnActivated() can be manually overwritten, and registration can be done individually for each required message for this recipient.")]
[RequiresDynamicCode(
"This method requires the generated CommunityToolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions type not to be removed to use the fast path. " +
"If that is present, the method is AOT safe, as the only methods being invoked to register the messages will be the ones produced by the source generator. " +
"If it isn't, this method will need to dynamically create the generic methods to register messages, which might not be available at runtime. " +
"Alternatively, OnActivated() can be manually overwritten, and registration can be done individually for each required message for this recipient.")]
protected virtual void OnActivated()
{
Messenger.RegisterAll(this);
Expand Down
11 changes: 9 additions & 2 deletions src/CommunityToolkit.Mvvm/Messaging/IMessengerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ public static bool IsRegistered<TMessage>(this IMessenger messenger, object reci
"This method requires the generated CommunityToolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions type not to be removed to use the fast path. " +
"If this type is removed by the linker, or if the target recipient was created dynamically and was missed by the source generator, a slower fallback " +
"path using a compiled LINQ expression will be used. This will have more overhead in the first invocation of this method for any given recipient type.")]
[RequiresDynamicCode(
"This method requires the generated CommunityToolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions type not to be removed to use the fast path. " +
"If that is present, the method is AOT safe, as the only methods being invoked to register the messages will be the ones produced by the source generator. " +
"If it isn't, this method will need to dynamically create the generic methods to register messages, which might not be available at runtime.")]
public static void RegisterAll(this IMessenger messenger, object recipient)
{
ArgumentNullException.ThrowIfNull(messenger);
Expand All @@ -113,7 +117,7 @@ public static void RegisterAll(this IMessenger messenger, object recipient)
// Try to get the cached delegate, if the generator has run correctly
Action<IMessenger, object>? registrationAction = DiscoveredRecipients.RegistrationMethods.GetValue(
recipient.GetType(),
[RequiresUnreferencedCode("The type of the current instance cannot be statically discovered.")] static (t) => LoadRegistrationMethodsForType(t));
LoadRegistrationMethodsForType);

if (registrationAction is not null)
{
Expand Down Expand Up @@ -144,6 +148,7 @@ public static void RegisterAll(this IMessenger messenger, object recipient)
"This method requires the generated CommunityToolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions type not to be removed to use the fast path. " +
"If this type is removed by the linker, or if the target recipient was created dynamically and was missed by the source generator, a slower fallback " +
"path using a compiled LINQ expression will be used. This will have more overhead in the first invocation of this method for any given recipient type.")]
[RequiresDynamicCode("The generic methods to register messages might not be available at runtime.")]
public static void RegisterAll<TToken>(this IMessenger messenger, object recipient, TToken token)
where TToken : IEquatable<TToken>
{
Expand All @@ -156,6 +161,7 @@ public static void RegisterAll<TToken>(this IMessenger messenger, object recipie
// target recipient type, and just invoke it to get the delegate to cache and use later.
// In this case we also need to create a generic instantiation of the target method first.
[RequiresUnreferencedCode("The type of the current instance cannot be statically discovered.")]
[RequiresDynamicCode("The generic methods to register messages might not be available at runtime.")]
static Action<IMessenger, object, TToken> LoadRegistrationMethodsForType(Type recipientType)
{
if (recipientType.Assembly.GetType("CommunityToolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions") is Type extensionsType &&
Expand All @@ -173,6 +179,7 @@ static Action<IMessenger, object, TToken> LoadRegistrationMethodsForType(Type re
// This method is only invoked once per recipient type and token type, so we're not
// worried about making it super efficient, and we can use the LINQ code for clarity.
// The LINQ codegen bloat is not really important for the same reason.
[RequiresDynamicCode("The generic methods to register messages might not be available at runtime.")]
static Action<IMessenger, object, TToken> LoadRegistrationMethodsForTypeFallback(Type recipientType)
{
// Get the collection of validation methods
Expand Down Expand Up @@ -231,7 +238,7 @@ from registrationMethod in registrationMethods
// For more info on this, see the related issue at https://github.com/dotnet/roslyn/issues/5835.
Action<IMessenger, object, TToken> registrationAction = DiscoveredRecipients<TToken>.RegistrationMethods.GetValue(
recipient.GetType(),
[RequiresUnreferencedCode("The type of the current instance cannot be statically discovered.")] static (t) => LoadRegistrationMethodsForType(t));
LoadRegistrationMethodsForType);

// Invoke the cached delegate to actually execute the message registration
registrationAction(messenger, recipient, token);
Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<!-- Include PolySharp to generate polyfills for all projects (on their .NET Standard 2.x targets) -->
<ItemGroup>
<PackageReference Include="PolySharp" Version="1.13.1">
<PackageReference Include="PolySharp" Version="1.14.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>build; analyzers</IncludeAssets>
</PackageReference>
Expand Down
9 changes: 7 additions & 2 deletions src/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,23 @@
<Import Project="..\Directory.Build.targets" />

<!-- Define NETSTANDARD2_1_OR_GREATER for .NET Standard 2.1 targets and above -->
<PropertyGroup Condition="'$(TargetFramework)' == 'net6.0' OR '$(TargetFramework)' == 'net6.0' OR '$(TargetFramework)' == 'net7.0'">
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'netstandard2.1'))">
<DefineConstants>NETSTANDARD2_1_OR_GREATER</DefineConstants>
</PropertyGroup>

<!-- Configure trimming for projects on .NET 6 and above -->
<PropertyGroup Condition="'$(TargetFramework)' == 'net6.0' OR '$(TargetFramework)' == 'net7.0'">
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0'))">
<IsTrimmable>true</IsTrimmable>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
<EnableAotAnalyzer>true</EnableAotAnalyzer>
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
</PropertyGroup>

<!-- Set the AOT property directly on .NET 8 and above -->
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
<IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>

<!--
The following target has been ported from TerraFX.Interop.Windows.
See: https://github.com/terrafx/terrafx.interop.windows.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks>
<TargetFrameworks>net472;net6.0;net7.0;net8.0</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading