Skip to content

Commit 8463df9

Browse files
author
Adrian Hall
committed
(#149) Updated xUnit, fixed .NET 9 synchronization context bug from .NET 9 performance improvements.
1 parent 8a4ccc2 commit 8463df9

File tree

4 files changed

+15
-83
lines changed

4 files changed

+15
-83
lines changed

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
<PackageVersion Include="System.Text.Json" Version="8.0.5" />
3434
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
3535
<PackageVersion Include="System.Threading.Tasks.Dataflow" Version="8.0.1" />
36-
<PackageVersion Include="xunit" Version="2.7.0" />
36+
<PackageVersion Include="xunit" Version="2.9.2" />
3737
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.7" />
3838
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
3939
<PackageVersion Include="coverlet.msbuild" Version="6.0.2" />

src/CommunityToolkit.Datasync.Client/Paging/ConcurrentObservableCollection.cs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace CommunityToolkit.Datasync.Client;
1616
/// <typeparam name="T"></typeparam>
1717
public class ConcurrentObservableCollection<T> : ObservableCollection<T>
1818
{
19-
private readonly SynchronizationContext context = SynchronizationContext.Current!;
19+
private readonly SynchronizationContext? currentContext = SynchronizationContext.Current;
2020
private bool suppressNotification = false;
2121

2222
/// <summary>
@@ -151,31 +151,30 @@ public bool ReplaceIf(Func<T, bool> match, T replacement)
151151
/// </summary>
152152
/// <param name="e">The event arguments</param>
153153
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
154-
=> DispatchCallback(new SynchronizationContextAdapter(this.context), RaiseCollectionChanged, e);
154+
{
155+
if (this.currentContext is null || SynchronizationContext.Current == this.currentContext)
156+
{
157+
RaiseCollectionChanged(e);
158+
}
159+
else
160+
{
161+
this.currentContext.Send(RaiseCollectionChanged, e);
162+
}
163+
}
155164

156165
/// <summary>
157166
/// Event trigger to indicate that a property has changed in a thread-safe way.
158167
/// </summary>
159168
/// <param name="e">The event arguments</param>
160169
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
161-
=> DispatchCallback(new SynchronizationContextAdapter(this.context), RaisePropertyChanged, e);
162-
163-
/// <summary>
164-
/// Dispatches the callback to the synchronization context. If the synchronization context is
165-
/// the current one, we can avoid a dispatch and just call the callback directly.
166-
/// </summary>
167-
/// <param name="context">The context to send the request to.</param>
168-
/// <param name="callback">The callback method.</param>
169-
/// <param name="param">The parameter for the callback method.</param>
170-
internal static void DispatchCallback(ISynchronizationContext context, SendOrPostCallback callback, object? param)
171170
{
172-
if (context.IsCurrentContext())
171+
if (this.currentContext is null || SynchronizationContext.Current == this.currentContext)
173172
{
174-
callback(param);
173+
RaisePropertyChanged(e);
175174
}
176175
else
177176
{
178-
context.Send(callback, param);
177+
this.currentContext.Send(RaisePropertyChanged, e);
179178
}
180179
}
181180

src/CommunityToolkit.Datasync.Client/Paging/SynchronizationContextAdapter.cs

Lines changed: 0 additions & 31 deletions
This file was deleted.

tests/CommunityToolkit.Datasync.Client.Test/Paging/ConcurrentObservableCollection_Tests.cs

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -180,40 +180,4 @@ public void ReplaceIf_False_IfNoMatch()
180180
actual.Should().BeFalse();
181181
this.movies.Should().HaveCount(count).And.NotContain(item);
182182
}
183-
184-
[Fact]
185-
public void DispatchCallback_DispatchesToSynchronizationContext()
186-
{
187-
int contextCaller = 0;
188-
int functionCaller = 0;
189-
190-
void dispatcher(object p) { functionCaller++; }
191-
192-
ISynchronizationContext context = Substitute.For<ISynchronizationContext>();
193-
context.IsCurrentContext().Returns(false);
194-
context.When(x => x.Send(Arg.Any<SendOrPostCallback>(), Arg.Any<object>())).Do(x => contextCaller++);
195-
196-
ConcurrentObservableCollection<InMemoryMovie>.DispatchCallback(context, dispatcher, new object());
197-
198-
contextCaller.Should().Be(1);
199-
functionCaller.Should().Be(0);
200-
}
201-
202-
[Fact]
203-
public void DispatchCallback_DispatchesLocally()
204-
{
205-
int contextCaller = 0;
206-
int functionCaller = 0;
207-
208-
void dispatcher(object p) { functionCaller++; }
209-
210-
ISynchronizationContext context = Substitute.For<ISynchronizationContext>();
211-
context.IsCurrentContext().Returns(true);
212-
context.When(x => x.Send(Arg.Any<SendOrPostCallback>(), Arg.Any<object>())).Do(x => contextCaller++);
213-
214-
ConcurrentObservableCollection<InMemoryMovie>.DispatchCallback(context, dispatcher, new object());
215-
216-
contextCaller.Should().Be(0);
217-
functionCaller.Should().Be(1);
218-
}
219183
}

0 commit comments

Comments
 (0)