Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable nullable reference types #242

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions Source/ReactiveProperty.Core/IReactiveProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public interface IReactiveProperty : IReadOnlyReactiveProperty, IHasErrors, INot
/// Gets or sets the value.
/// </summary>
/// <value>The value.</value>
new object Value { get; set; }
new object? Value { get; set; }
}

/// <summary>
Expand All @@ -25,6 +25,6 @@ public interface IReactiveProperty<T> : IReactiveProperty, IReadOnlyReactiveProp
/// Gets or sets the value.
/// </summary>
/// <value>The value.</value>
new T Value { get; set; }
new T? Value { get; set; }
}
}
4 changes: 2 additions & 2 deletions Source/ReactiveProperty.Core/IReadOnlyReactiveProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public interface IReadOnlyReactiveProperty : INotifyPropertyChanged
/// Gets the value.
/// </summary>
/// <value>The value.</value>
object Value { get; }
object? Value { get; }
}

/// <summary>
Expand All @@ -23,6 +23,6 @@ public interface IReadOnlyReactiveProperty<out T> : IReadOnlyReactiveProperty, I
/// Gets the value.
/// </summary>
/// <value>The value.</value>
new T Value { get; }
new T? Value { get; }
}
}
30 changes: 14 additions & 16 deletions Source/ReactiveProperty.Core/Internals/ExpressionTreeUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,46 @@ internal static class ExpressionTreeUtils
{
public static string GetPropertyPath<TType, TProperty>(Expression<Func<TType, TProperty>> propertySelector)
{
if (!(propertySelector.Body is MemberExpression memberExpression))
{
if (!(propertySelector.Body is UnaryExpression unaryExpression)) { throw new ArgumentException(nameof(propertySelector)); }
memberExpression = unaryExpression.Operand as MemberExpression;
if (memberExpression == null) { throw new ArgumentException(nameof(propertySelector)); }
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xxxxxxxx

var memberExpression = GetMemberExpressionFromPropertySelector(propertySelector);
var tokens = new LinkedList<string>();
while (memberExpression != null)
{
tokens.AddFirst(memberExpression.Member.Name);
memberExpression = memberExpression.Expression as MemberExpression;
if (memberExpression is not MemberExpression nextToken) { break; }
memberExpression = nextToken;
}

return string.Join(".", tokens);
}


public static string GetPropertyName<TType, TProperty>(Expression<Func<TType, TProperty>> propertySelector)
public static string GetPropertyName<TType, TProperty>(Expression<Func<TType, TProperty>> propertySelector) =>
GetMemberExpressionFromPropertySelector(propertySelector).Member.Name;

private static MemberExpression GetMemberExpressionFromPropertySelector<TType, TProperty>(Expression<Func<TType, TProperty>> propertySelector)
{
if (!(propertySelector.Body is MemberExpression memberExpression))
if (propertySelector.Body is not MemberExpression memberExpression)
{
if (!(propertySelector.Body is UnaryExpression unaryExpression)) { throw new ArgumentException(nameof(propertySelector)); }
memberExpression = unaryExpression.Operand as MemberExpression;
if (memberExpression == null) { throw new ArgumentException(nameof(propertySelector)); }
if (propertySelector.Body is not UnaryExpression unaryExpression) { throw new ArgumentException(nameof(propertySelector)); }
if (unaryExpression.Operand is not MemberExpression memberExpressionForUnary) { throw new ArgumentException(nameof(propertySelector)); }
memberExpression = memberExpressionForUnary;
}

return memberExpression.Member.Name;
return memberExpression;
}

public static bool IsNestedPropertyPath<TSubject, TProperty>(Expression<Func<TSubject, TProperty>> propertySelector)
{
if (propertySelector.Body is MemberExpression member)
{
return !(member.Expression is ParameterExpression);
return member.Expression is not ParameterExpression;
};

if (propertySelector.Body is UnaryExpression unary)
{
if (unary.Operand is MemberExpression unaryMember)
{
return !(unaryMember.Expression is ParameterExpression);
return unaryMember.Expression is not ParameterExpression;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Reactive.Bindings.Internals
{
internal interface IObserverLinkedList<T>
{
void UnsubscribeNode(ObserverNode<T> node);
void UnsubscribeNode(ObserverNode<T?> node);
}

}
6 changes: 3 additions & 3 deletions Source/ReactiveProperty.Core/Internals/ObserverNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ internal sealed class ObserverNode<T> : IObserver<T>, IDisposable
private readonly IObserver<T> _observer;
private IObserverLinkedList<T> _list;

public ObserverNode<T> Previous { get; set; }
public ObserverNode<T>? Previous { get; set; }

public ObserverNode<T> Next { get; set; }
public ObserverNode<T>? Next { get; set; }

public ObserverNode(IObserverLinkedList<T> list, IObserver<T> observer)
{
Expand All @@ -38,7 +38,7 @@ public void OnCompleted()
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0059:Unnecessary assignment of a value", Justification = "<Pending>")]
public void Dispose()
{
var sourceList = Interlocked.Exchange(ref _list, null);
var sourceList = Interlocked.Exchange(ref _list, null!);
if (sourceList != null)
{
sourceList.UnsubscribeNode(this);
Expand Down
3 changes: 2 additions & 1 deletion Source/ReactiveProperty.Core/ReactiveProperty.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

<PropertyGroup>
<PackageId>ReactiveProperty.Core</PackageId>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFrameworks>netstandard2.0;netcoreapp3.1;net5.0</TargetFrameworks>
<AssemblyName>ReactiveProperty.Core</AssemblyName>
<SignAssembly>true</SignAssembly>
<Nullable>enable</Nullable>
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
<Description>ReactiveProperty.Core includes minimum core classes such as ReactivePropertySlim and ReadOnlyReactivePropertySlim.</Description>
</PropertyGroup>
Expand Down
38 changes: 18 additions & 20 deletions Source/ReactiveProperty.Core/ReactivePropertySlim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,24 @@ public class ReactivePropertySlim<T> : IReactiveProperty<T>, IObserverLinkedList
private const int IsDisposedFlagNumber = 1 << 9; // (reserve 0 ~ 8)

// minimize field count
private T _latestValue;
private T? _latestValue;

private ReactivePropertyMode _mode; // None = 0, DistinctUntilChanged = 1, RaiseLatestValueOnSubscribe = 2, Disposed = (1 << 9)
private readonly IEqualityComparer<T> _equalityComparer;
private ObserverNode<T> _root;
private ObserverNode<T> _last;
private ObserverNode<T?>? _root;
private ObserverNode<T?>? _last;

/// <summary>
/// Occurs when a property value changes.
/// </summary>
/// <returns></returns>
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangedEventHandler? PropertyChanged;

/// <summary>
/// Gets or sets the value.
/// </summary>
/// <value>The value.</value>
public T Value
public T? Value
{
get
{
Expand Down Expand Up @@ -64,7 +64,7 @@ public T Value
/// <value><c>true</c> if this instance is disposed; otherwise, <c>false</c>.</value>
public bool IsDisposed => (int)_mode == IsDisposedFlagNumber;

object IReactiveProperty.Value
object? IReactiveProperty.Value
{
get
{
Expand Down Expand Up @@ -105,14 +105,14 @@ object IReadOnlyReactiveProperty.Value
/// <param name="initialValue">The initial value.</param>
/// <param name="mode">The mode.</param>
/// <param name="equalityComparer">The equality comparer.</param>
public ReactivePropertySlim(T initialValue = default, ReactivePropertyMode mode = ReactivePropertyMode.Default, IEqualityComparer<T> equalityComparer = null)
public ReactivePropertySlim(T? initialValue = default, ReactivePropertyMode mode = ReactivePropertyMode.Default, IEqualityComparer<T>? equalityComparer = null)
{
_latestValue = initialValue;
_mode = mode;
_equalityComparer = equalityComparer ?? EqualityComparer<T>.Default;
}

private void OnNextAndRaiseValueChanged(ref T value)
private void OnNextAndRaiseValueChanged(ref T? value)
{
// call source.OnNext
var node = _root;
Expand Down Expand Up @@ -169,7 +169,7 @@ public IDisposable Subscribe(IObserver<T> observer)
return next;
}

void IObserverLinkedList<T>.UnsubscribeNode(ObserverNode<T> node)
void IObserverLinkedList<T>.UnsubscribeNode(ObserverNode<T?> node)
{
if (node == _root)
{
Expand Down Expand Up @@ -231,7 +231,7 @@ public override string ToString()

IObservable<bool> IHasErrors.ObserveHasErrors => throw new NotSupportedException();

event EventHandler<DataErrorsChangedEventArgs> INotifyDataErrorInfo.ErrorsChanged
event EventHandler<DataErrorsChangedEventArgs>? INotifyDataErrorInfo.ErrorsChanged
{
add
{
Expand All @@ -241,7 +241,7 @@ public override string ToString()
}
}

IEnumerable INotifyDataErrorInfo.GetErrors(string propertyName)
IEnumerable INotifyDataErrorInfo.GetErrors(string? propertyName)
{
return System.Linq.Enumerable.Empty<object>();
}
Expand All @@ -251,26 +251,25 @@ IEnumerable INotifyDataErrorInfo.GetErrors(string propertyName)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <seealso cref="Reactive.Bindings.IReadOnlyReactiveProperty{T}"/>
/// <seealso cref="Reactive.Bindings.IObserverLinkedList{T}"/>
/// <seealso cref="System.IObserver{T}"/>
public class ReadOnlyReactivePropertySlim<T> : IReadOnlyReactiveProperty<T>, IObserverLinkedList<T>, IObserver<T>
{
private const int IsDisposedFlagNumber = 1 << 9; // (reserve 0 ~ 8)

// minimize field count
private T _latestValue;
private T? _latestValue;

private IDisposable _sourceSubscription;
private ReactivePropertyMode _mode; // None = 0, DistinctUntilChanged = 1, RaiseLatestValueOnSubscribe = 2, Disposed = (1 << 9)
private readonly IEqualityComparer<T> _equalityComparer;
private ObserverNode<T> _root;
private ObserverNode<T> _last;
private ObserverNode<T>? _root;
private ObserverNode<T>? _last;

/// <summary>
/// Occurs when a property value changes.
/// </summary>
/// <returns></returns>
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangedEventHandler? PropertyChanged;

/// <summary>
/// Gets the value.
Expand Down Expand Up @@ -305,7 +304,7 @@ public T Value
/// <param name="initialValue">The initial value.</param>
/// <param name="mode">The mode.</param>
/// <param name="equalityComparer">The equality comparer.</param>
public ReadOnlyReactivePropertySlim(IObservable<T> source, T initialValue = default, ReactivePropertyMode mode = ReactivePropertyMode.DistinctUntilChanged | ReactivePropertyMode.RaiseLatestValueOnSubscribe, IEqualityComparer<T> equalityComparer = null)
public ReadOnlyReactivePropertySlim(IObservable<T> source, T? initialValue = default, ReactivePropertyMode mode = ReactivePropertyMode.DistinctUntilChanged | ReactivePropertyMode.RaiseLatestValueOnSubscribe, IEqualityComparer<T>? equalityComparer = null)
{
_latestValue = initialValue;
_mode = mode;
Expand Down Expand Up @@ -355,7 +354,7 @@ public IDisposable Subscribe(IObserver<T> observer)
return next;
}

void IObserverLinkedList<T>.UnsubscribeNode(ObserverNode<T> node)
void IObserverLinkedList<T>.UnsubscribeNode(ObserverNode<T?> node)
{
if (node == _root)
{
Expand Down Expand Up @@ -455,7 +454,6 @@ public override string ToString()
/// <summary>
/// </summary>
/// <seealso cref="Reactive.Bindings.IReadOnlyReactiveProperty{T}"/>
/// <seealso cref="Reactive.Bindings.IObserverLinkedList{T}"/>
/// <seealso cref="System.IObserver{T}"/>
public static class ReadOnlyReactivePropertySlim
{
Expand All @@ -468,7 +466,7 @@ public static class ReadOnlyReactivePropertySlim
/// <param name="mode">The mode.</param>
/// <param name="equalityComparer">The equality comparer.</param>
/// <returns></returns>
public static ReadOnlyReactivePropertySlim<T> ToReadOnlyReactivePropertySlim<T>(this IObservable<T> source, T initialValue = default, ReactivePropertyMode mode = ReactivePropertyMode.DistinctUntilChanged | ReactivePropertyMode.RaiseLatestValueOnSubscribe, IEqualityComparer<T> equalityComparer = null)
public static ReadOnlyReactivePropertySlim<T> ToReadOnlyReactivePropertySlim<T>(this IObservable<T> source, T? initialValue = default, ReactivePropertyMode mode = ReactivePropertyMode.DistinctUntilChanged | ReactivePropertyMode.RaiseLatestValueOnSubscribe, IEqualityComparer<T>? equalityComparer = null)
{
return new ReadOnlyReactivePropertySlim<T>(source, initialValue, mode, equalityComparer);
}
Expand Down
16 changes: 8 additions & 8 deletions Source/ReactiveProperty.NETStandard/AsyncReactiveCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public class AsyncReactiveCommand<T> : ICommand, IDisposable
/// Occurs when changes occur that affect whether or not the command should execute.
/// </summary>
/// <returns></returns>
public event EventHandler CanExecuteChanged;
public event EventHandler? CanExecuteChanged;

private readonly object gate = new object();
private readonly IReactiveProperty<bool> canExecute;
Expand Down Expand Up @@ -103,7 +103,7 @@ public AsyncReactiveCommand(IObservable<bool> canExecuteSource)
/// <summary>
/// CanExecute is automatically changed when executing to false and finished to true.
/// </summary>
public AsyncReactiveCommand(IObservable<bool> canExecuteSource, IReactiveProperty<bool> sharedCanExecute)
public AsyncReactiveCommand(IObservable<bool> canExecuteSource, IReactiveProperty<bool>? sharedCanExecute)
{
canExecute = sharedCanExecute ?? new ReactivePropertySlim<bool>(true);
sourceSubscription = canExecute.CombineLatest(canExecuteSource, (x, y) => x && y)
Expand Down Expand Up @@ -140,20 +140,20 @@ public bool CanExecute()
/// <summary>
/// Return current canExecute status. parameter is ignored.
/// </summary>
bool ICommand.CanExecute(object parameter)
bool ICommand.CanExecute(object? parameter)
{
return isDisposed ? false : isCanExecute;
}

/// <summary>
/// Push parameter to subscribers, when executing CanExecuting is changed to false.
/// </summary>
public async void Execute(T parameter) => await ExecuteAsync(parameter);
public async void Execute(T? parameter) => await ExecuteAsync(parameter);

/// <summary>
/// Push parameter to subscribers, when executing CanExecuting is changed to false.
/// </summary>
public async Task ExecuteAsync(T parameter)
public async Task ExecuteAsync(T? parameter)
{
if (isCanExecute)
{
Expand Down Expand Up @@ -195,7 +195,7 @@ public async Task ExecuteAsync(T parameter)
/// <summary>
/// Push parameter to subscribers, when executing CanExecuting is changed to false.
/// </summary>
void ICommand.Execute(object parameter) => Execute((T)parameter);
void ICommand.Execute(object? parameter) => Execute((T)parameter);

/// <summary>
/// Subscribe execute.
Expand Down Expand Up @@ -300,7 +300,7 @@ public static class AsyncReactiveCommandExtensions
/// <param name="asyncAction">Action</param>
/// <param name="postProcess">Handling of the subscription.</param>
/// <returns>Same of self argument</returns>
public static AsyncReactiveCommand WithSubscribe(this AsyncReactiveCommand self, Func<Task> asyncAction, Action<IDisposable> postProcess = null)
public static AsyncReactiveCommand WithSubscribe(this AsyncReactiveCommand self, Func<Task> asyncAction, Action<IDisposable>? postProcess = null)
{
var d = self.Subscribe(asyncAction);
postProcess?.Invoke(d);
Expand All @@ -315,7 +315,7 @@ public static AsyncReactiveCommand WithSubscribe(this AsyncReactiveCommand self,
/// <param name="asyncAction">Action</param>
/// <param name="postProcess">Handling of the subscription.</param>
/// <returns>Same of self argument</returns>
public static AsyncReactiveCommand<T> WithSubscribe<T>(this AsyncReactiveCommand<T> self, Func<T, Task> asyncAction, Action<IDisposable> postProcess = null)
public static AsyncReactiveCommand<T> WithSubscribe<T>(this AsyncReactiveCommand<T> self, Func<T, Task> asyncAction, Action<IDisposable>? postProcess = null)
{
var d = self.Subscribe(asyncAction);
postProcess?.Invoke(d);
Expand Down