docs/RxSchedulers.md
When using RxApp.MainThreadScheduler or RxApp.TaskpoolScheduler in your code, since the entire RxApp class triggers initialization that is marked with RequiresUnreferencedCode attributes, any code that consumes these schedulers must also be marked with the same attributes.
This is particularly problematic when creating observables in ViewModels, Repositories, or other deeper code that is consumed by multiple sources, as it forces all consumers to add RequiresUnreferencedCode attributes.
The new RxSchedulers static class provides access to the same scheduler functionality without requiring unreferenced code attributes. This class contains only the scheduler properties and doesn't trigger the Splat dependency injection initialization that requires reflection.
// Old way - requires RequiresUnreferencedCode attribute
[RequiresUnreferencedCode("Uses RxApp which may require unreferenced code")]
public IObservable<string> GetDataOld()
{
return Observable.Return("data")
.ObserveOn(RxApp.MainThreadScheduler); // Triggers RequiresUnreferencedCode
}
// New way - no attributes required
public IObservable<string> GetDataNew()
{
return Observable.Return("data")
.ObserveOn(RxSchedulers.MainThreadScheduler); // No attributes needed!
}
public class MyViewModel : ReactiveObject
{
private readonly ObservableAsPropertyHelper<string> _greeting;
public MyViewModel()
{
// Using RxSchedulers avoids RequiresUnreferencedCode
_greeting = this.WhenAnyValue(x => x.Name)
.Select(name => $"Hello, {name ?? "World"}!")
.ObserveOn(RxSchedulers.MainThreadScheduler) // No attributes needed!
.ToProperty(this, nameof(Greeting), scheduler: RxSchedulers.MainThreadScheduler);
}
public string? Name { get; set; }
public string Greeting => _greeting.Value;
}
public class DataRepository
{
public IObservable<string> GetProcessedData()
{
// Using RxSchedulers in repository code doesn't force consumers
// to add RequiresUnreferencedCode attributes
return GetRawData()
.ObserveOn(RxSchedulers.TaskpoolScheduler) // Background processing
.Select(ProcessData)
.ObserveOn(RxSchedulers.MainThreadScheduler); // UI updates
}
}
// New factory methods that use RxSchedulers internally
var property1 = ReactiveProperty<string>.Create(); // No attributes required
var property2 = ReactiveProperty<string>.Create("initial value");
var property3 = ReactiveProperty<int>.Create(42, skipCurrentValueOnSubscribe: false, allowDuplicateValues: true);
RxSchedulers.MainThreadScheduler - Scheduler for UI thread operations (no unit test detection)RxSchedulers.TaskpoolScheduler - Scheduler for background operations (no unit test detection)ReactiveProperty<T>.Create() - Creates with default schedulerReactiveProperty<T>.Create(T initialValue) - Creates with initial valueReactiveProperty<T>.Create(T initialValue, bool skipCurrentValueOnSubscribe, bool allowDuplicateValues) - Full configurationReactiveProperty<T>.Create(T initialValue, IScheduler scheduler, bool skipCurrentValueOnSubscribe, bool allowDuplicateValues) - Custom schedulerRxApp schedulers still work as before - no breaking changesRxApp and RxSchedulers are kept synchronized when schedulers are setRxApp schedulersRxSchedulersRxSchedulers when:RequiresUnreferencedCode attributesRxApp schedulers when:RxApp featuresRequiresUnreferencedCodeTo migrate existing code from RxApp to RxSchedulers:
RxApp.MainThreadScheduler with RxSchedulers.MainThreadSchedulerRxApp.TaskpoolScheduler with RxSchedulers.TaskpoolSchedulerRequiresUnreferencedCode and RequiresDynamicCode attributes if they were only needed for scheduler accessReactiveProperty<T>.Create() factory methods instead of constructorsRxSchedulers provides a simplified version without unit test detectionDefaultScheduler.Instance for main thread and TaskPoolScheduler.Default for background