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

Support Nullable Reference Types #344

Closed
wants to merge 2 commits into from
Closed
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
2 changes: 1 addition & 1 deletion 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>
/// Forces the notify.
Expand Down
2 changes: 1 addition & 1 deletion 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 Down
14 changes: 7 additions & 7 deletions Source/ReactiveProperty.Core/Internals/AccessorCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ internal static class AccessorCache<TType>
public static Func<TType, TProperty> LookupGet<TProperty>(Expression<Func<TType, TProperty>> propertySelector, out string propertyName)
{
propertyName = ExpressionTreeUtils.GetPropertyName(propertySelector);
Delegate accessor;
Delegate? accessor;

lock (s_getCache)
{
Expand All @@ -48,7 +48,7 @@ public static Func<TType, TProperty> LookupGet<TProperty>(Expression<Func<TType,
public static Func<TType, TProperty> LookupNestedGet<TProperty>(Expression<Func<TType, TProperty>> propertySelector, out string propertyName)
{
propertyName = ExpressionTreeUtils.GetPropertyPath(propertySelector);
Delegate accessor;
Delegate? accessor;

lock (s_getCache)
{
Expand All @@ -72,7 +72,7 @@ public static Func<TType, TProperty> LookupNestedGet<TProperty>(Expression<Func<
public static Action<TType, TProperty> LookupSet<TProperty>(Expression<Func<TType, TProperty>> propertySelector, out string propertyName)
{
propertyName = ExpressionTreeUtils.GetPropertyName(propertySelector);
Delegate accessor;
Delegate? accessor;

lock (s_setCache)
{
Expand Down Expand Up @@ -113,7 +113,7 @@ private static Dictionary<string, Delegate> GetGetCacheByType(Type type)
}

var accessorType = GetAccessorCacheTypeByType(type);
cache = (Dictionary<string, Delegate>)accessorType.GetField("s_getCache", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
cache = (Dictionary<string, Delegate>)accessorType.GetField("s_getCache", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null)!;
_getCache.Add(type, cache);
return cache;
}
Expand All @@ -129,7 +129,7 @@ private static Dictionary<string, Delegate> GetSetCacheByType(Type type)
}

var accessorType = GetAccessorCacheTypeByType(type);
cache = (Dictionary<string, Delegate>)accessorType.GetField("s_setCache", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
cache = (Dictionary<string, Delegate>)accessorType.GetField("s_setCache", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null)!;
_setCache.Add(type, cache);
return cache;
}
Expand Down Expand Up @@ -182,15 +182,15 @@ public static Delegate LookupSet(Type type, string propertyName)

private static Delegate CreateAndCacheGetAccessor(Type type, string propertyName, Dictionary<string, Delegate> cache)
{
var propertyInfo = type.GetProperty(propertyName);
var propertyInfo = type.GetProperty(propertyName) ?? throw new ArgumentException($"{propertyName} is not found on {type.FullName}");
var accessor = CreateGetAccessor(type, propertyInfo);
cache.Add(propertyName, accessor);
return accessor;
}

private static Delegate CreateAndCacheSetAccessor(Type type, string propertyName, Dictionary<string, Delegate> cache)
{
var propertyInfo = type.GetProperty(propertyName);
var propertyInfo = type.GetProperty(propertyName) ?? throw new ArgumentException($"{propertyName} is not found on {type.FullName}");
var accessor = CreateSetAccessor(type, propertyInfo);
cache.Add(propertyName, accessor);
return accessor;
Expand Down
8 changes: 5 additions & 3 deletions Source/ReactiveProperty.Core/Internals/ExpressionTreeUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ internal static class ExpressionTreeUtils
{
public static string GetPropertyPath<TType, TProperty>(Expression<Func<TType, TProperty>> propertySelector)
{
if (!(propertySelector.Body is MemberExpression memberExpression))
var memberExpression = propertySelector.Body as MemberExpression;
if (memberExpression == null)
{
if (!(propertySelector.Body is UnaryExpression unaryExpression)) { throw new ArgumentException(nameof(propertySelector)); }
if (propertySelector.Body is not UnaryExpression unaryExpression) { throw new ArgumentException(nameof(propertySelector)); }
memberExpression = unaryExpression.Operand as MemberExpression;
if (memberExpression == null) { throw new ArgumentException(nameof(propertySelector)); }
}
Expand All @@ -29,7 +30,8 @@ public static string GetPropertyPath<TType, TProperty>(Expression<Func<TType, TP

public static string GetPropertyName<TType, TProperty>(Expression<Func<TType, TProperty>> propertySelector)
{
if (!(propertySelector.Body is MemberExpression memberExpression))
var memberExpression = propertySelector.Body as MemberExpression;
if (memberExpression == null)
{
if (!(propertySelector.Body is UnaryExpression unaryExpression)) { throw new ArgumentException(nameof(propertySelector)); }
memberExpression = unaryExpression.Operand as MemberExpression;
Expand Down
6 changes: 3 additions & 3 deletions Source/ReactiveProperty.Core/Internals/ObserverNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ namespace Reactive.Bindings.Internals;
internal sealed class ObserverNode<T> : IObserver<T>, IDisposable
{
private readonly IObserver<T> _observer;
private IObserverLinkedList<T> _list;
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 Down
40 changes: 20 additions & 20 deletions Source/ReactiveProperty.Core/ReactivePropertySlim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ public class ReactivePropertySlim<T> : IReactiveProperty<T>, IObserverLinkedList

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.
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 All @@ -73,11 +73,11 @@ object IReactiveProperty.Value

set
{
Value = (T)value;
Value = (T)value!;
}
}

object IReadOnlyReactiveProperty.Value
object? IReadOnlyReactiveProperty.Value
{
get
{
Expand Down Expand Up @@ -105,7 +105,7 @@ 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;
Expand Down Expand Up @@ -162,7 +162,7 @@ public IDisposable Subscribe(IObserver<T> observer)
}
else
{
_last.Next = next;
_last!.Next = next;
next.Previous = _last;
_last = next;
}
Expand Down Expand Up @@ -216,7 +216,7 @@ public void Dispose()
/// Returns a <see cref="string"/> that represents this instance.
/// </summary>
/// <returns>A <see cref="string"/> that represents this instance.</returns>
public override string ToString()
public override string? ToString()
{
return (_latestValue == null)
? "null"
Expand All @@ -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 @@ event EventHandler<DataErrorsChangedEventArgs> INotifyDataErrorInfo.ErrorsChange
}
}

IEnumerable INotifyDataErrorInfo.GetErrors(string propertyName)
IEnumerable INotifyDataErrorInfo.GetErrors(string? propertyName)
{
return System.Linq.Enumerable.Empty<object>();
}
Expand All @@ -260,17 +260,17 @@ public class ReadOnlyReactivePropertySlim<T> : IReadOnlyReactiveProperty<T>, IOb
// minimize field count
private T _latestValue;

private IDisposable _sourceSubscription;
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 All @@ -290,7 +290,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 IReadOnlyReactiveProperty.Value => Value;
object? IReadOnlyReactiveProperty.Value => Value;

private bool IsDistinctUntilChanged => (_mode & ReactivePropertyMode.DistinctUntilChanged) == ReactivePropertyMode.DistinctUntilChanged;

Expand All @@ -305,7 +305,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 @@ -347,7 +347,7 @@ public IDisposable Subscribe(IObserver<T> observer)
}
else
{
_last.Next = next;
_last!.Next = next;
next.Previous = _last;
_last = next;
}
Expand Down Expand Up @@ -444,7 +444,7 @@ void IObserver<T>.OnCompleted()
/// Returns a <see cref="string"/> that represents this instance.
/// </summary>
/// <returns>A <see cref="string"/> that represents this instance.</returns>
public override string ToString()
public override string? ToString()
{
return (_latestValue == null)
? "null"
Expand All @@ -468,7 +468,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
2 changes: 2 additions & 0 deletions Source/ReactiveProperty.NETStandard/ReactiveProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public ReactiveProperty()
{
}

#nullable disable
/// <summary>
/// PropertyChanged raise on ReactivePropertyScheduler
/// </summary>
Expand All @@ -101,6 +102,7 @@ public ReactiveProperty(
IEqualityComparer<T> equalityComparer = null)
: this(ReactivePropertyScheduler.Default, initialValue, mode, equalityComparer)
{ }
#nullable enable

/// <summary>
/// PropertyChanged raise on selected scheduler
Expand Down
1 change: 1 addition & 0 deletions Source/SharedProperties.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<RepositoryUrl>https://github.com/runceel/ReactiveProperty</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<LangVersion>10.0</LangVersion>
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
Expand Down