Browse Source

Add failing tests for #4733 and fix property accessor.

pull/4746/head
Dariusz Komosiński 5 years ago
parent
commit
8555fed86b
  1. 44
      src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
  2. 29
      tests/Avalonia.Base.UnitTests/Data/Core/ExpressionObserverTests_Property.cs

44
src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using Avalonia.Utilities;
@ -11,8 +12,11 @@ namespace Avalonia.Data.Core.Plugins
/// </summary>
public class InpcPropertyAccessorPlugin : IPropertyAccessorPlugin
{
private readonly Dictionary<(Type, string), PropertyInfo> _propertyLookup =
new Dictionary<(Type, string), PropertyInfo>();
/// <inheritdoc/>
public bool Match(object obj, string propertyName) => GetPropertyWithName(obj.GetType(), propertyName) != null;
public bool Match(object obj, string propertyName) => GetFirstPropertyWithName(obj.GetType(), propertyName) != null;
/// <summary>
/// Starts monitoring the value of a property on an object.
@ -30,7 +34,7 @@ namespace Avalonia.Data.Core.Plugins
reference.TryGetTarget(out object instance);
var p = GetPropertyWithName(instance.GetType(), propertyName);
var p = GetFirstPropertyWithName(instance.GetType(), propertyName);
if (p != null)
{
@ -44,12 +48,40 @@ namespace Avalonia.Data.Core.Plugins
}
}
private static PropertyInfo GetPropertyWithName(Type type, string propertyName)
private PropertyInfo GetFirstPropertyWithName(Type type, string propertyName)
{
const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.Static | BindingFlags.Instance;
var key = (type, propertyName);
if (!_propertyLookup.TryGetValue(key, out PropertyInfo propertyInfo))
{
propertyInfo = TryFindAndCacheProperty(type, propertyName);
}
return propertyInfo;
}
private PropertyInfo TryFindAndCacheProperty(Type type, string propertyName)
{
PropertyInfo found = null;
const BindingFlags bindingFlags =
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
var properties = type.GetProperties(bindingFlags);
foreach (PropertyInfo propertyInfo in properties)
{
if (propertyInfo.Name == propertyName)
{
found = propertyInfo;
break;
}
}
_propertyLookup.Add((type, propertyName), found);
return type.GetProperty(propertyName, bindingFlags);
return found;
}
private class Accessor : PropertyAccessorBase, IWeakSubscriber<PropertyChangedEventArgs>

29
tests/Avalonia.Base.UnitTests/Data/Core/ExpressionObserverTests_Property.cs

@ -600,6 +600,24 @@ namespace Avalonia.Base.UnitTests.Data.Core
result);
}
[Fact]
public void Should_Not_Throw_Exception_On_Duplicate_Properties()
{
// Repro of https://github.com/AvaloniaUI/Avalonia/issues/4733.
var source = new MyViewModel();
var target = new PropertyAccessorNode("Name", false);
target.Target = new WeakReference<object>(source);
var result = new List<object>();
target.Subscribe(x => result.Add(x));
}
public class MyViewModelBase { public object Name => "Name"; }
public class MyViewModel : MyViewModelBase { public new string Name => "NewName"; }
private interface INext
{
int PropertyChangedSubscriptionCount { get; }
@ -664,6 +682,17 @@ namespace Avalonia.Base.UnitTests.Data.Core
}
}
private class WithNewBar : Class1
{
private string _bar;
public new string Bar
{
get { return _bar; }
set { _bar = value; }
}
}
private class Class3 : Class1
{
}

Loading…
Cancel
Save