Skip to content

Commit a808c0c

Browse files
committed
Fix #6. Collect only observable fields.
1 parent 692f90f commit a808c0c

File tree

6 files changed

+119
-80
lines changed

6 files changed

+119
-80
lines changed

src/UnityMvvmToolkit.Core/Internal/BindingContextMemberProvider.cs

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -63,40 +63,49 @@ private static bool TryGetFieldHashCode(Type contextType, FieldInfo fieldInfo, o
6363
return TryGetHashCode(contextType, fieldInfo.Name, fieldInfo.FieldType, out hashCode);
6464
}
6565

66-
if (TryGetPropertyNameFromAttribute(fieldInfo, out var fieldName))
66+
if (HasObservableAttribute(fieldInfo, out var propertyName) == false)
6767
{
68-
return TryGetHashCode(contextType, fieldName, fieldInfo.FieldType, out hashCode);
68+
hashCode = default;
69+
return false;
6970
}
7071

71-
fieldName = fieldInfo.Name;
72+
return string.IsNullOrWhiteSpace(propertyName)
73+
? TryGetHashCode(contextType, GetFieldName(fieldInfo.Name), fieldInfo.FieldType, out hashCode)
74+
: TryGetHashCode(contextType, propertyName, fieldInfo.FieldType, out hashCode);
75+
}
7276

73-
if (fieldName.Length > 1)
77+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
78+
private static bool TryGetPropertyHashCode(Type contextType, PropertyInfo propertyInfo, out int hashCode)
79+
{
80+
if (propertyInfo.GetMethod.IsPrivate)
7481
{
75-
if (fieldName[0] == '_')
76-
{
77-
fieldName = fieldName[1..]; // TODO: Get rid of allocation.
78-
}
79-
80-
if (fieldName[0] == 'm' && fieldName[1] == '_')
81-
{
82-
fieldName = fieldName[2..]; // TODO: Get rid of allocation.
83-
}
82+
hashCode = default;
83+
return false;
8484
}
8585

86-
if (string.IsNullOrEmpty(fieldName))
86+
return TryGetHashCode(contextType, propertyInfo.Name, propertyInfo.PropertyType, out hashCode);
87+
}
88+
89+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
90+
private static bool TryGetHashCode(Type contextType, string memberName, Type memberType, out int hashCode)
91+
{
92+
if (typeof(IBaseCommand).IsAssignableFrom(memberType) ||
93+
typeof(IBaseProperty).IsAssignableFrom(memberType))
8794
{
88-
throw new InvalidOperationException($"Field name '{fieldName}' is not supported.");
95+
hashCode = HashCodeHelper.GetMemberHashCode(contextType, memberName);
96+
return true;
8997
}
9098

91-
return TryGetHashCode(contextType, fieldName, fieldInfo.FieldType, out hashCode);
99+
hashCode = default;
100+
return false;
92101
}
93102

94103
[MethodImpl(MethodImplOptions.AggressiveInlining)]
95-
private static bool TryGetPropertyNameFromAttribute(MemberInfo fieldInfo, out string propertyName)
104+
private static bool HasObservableAttribute(MemberInfo fieldInfo, out string propertyName)
96105
{
97106
var observableAttribute = fieldInfo.GetCustomAttribute<ObservableAttribute>();
98107

99-
if (observableAttribute == null || string.IsNullOrWhiteSpace(observableAttribute.PropertyName))
108+
if (observableAttribute == null)
100109
{
101110
propertyName = default;
102111
return false;
@@ -107,29 +116,29 @@ private static bool TryGetPropertyNameFromAttribute(MemberInfo fieldInfo, out st
107116
}
108117

109118
[MethodImpl(MethodImplOptions.AggressiveInlining)]
110-
private static bool TryGetPropertyHashCode(Type contextType, PropertyInfo propertyInfo, out int hashCode)
119+
private static string GetFieldName(string fieldName)
111120
{
112-
if (propertyInfo.GetMethod.IsPrivate)
121+
var resultName = fieldName;
122+
123+
if (resultName.Length > 1)
113124
{
114-
hashCode = default;
115-
return false;
116-
}
125+
if (resultName[0] == '_')
126+
{
127+
resultName = resultName[1..]; // TODO: Get rid of allocation.
128+
}
117129

118-
return TryGetHashCode(contextType, propertyInfo.Name, propertyInfo.PropertyType, out hashCode);
119-
}
130+
if (resultName[0] == 'm' && resultName[1] == '_')
131+
{
132+
resultName = resultName[2..]; // TODO: Get rid of allocation.
133+
}
134+
}
120135

121-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
122-
private static bool TryGetHashCode(Type contextType, string memberName, Type memberType, out int hashCode)
123-
{
124-
if (typeof(IBaseCommand).IsAssignableFrom(memberType) ||
125-
typeof(IBaseProperty).IsAssignableFrom(memberType))
136+
if (string.IsNullOrEmpty(resultName))
126137
{
127-
hashCode = HashCodeHelper.GetMemberHashCode(contextType, memberName);
128-
return true;
138+
throw new InvalidOperationException($"Field name '{resultName}' is not supported.");
129139
}
130140

131-
hashCode = default;
132-
return false;
141+
return resultName;
133142
}
134143
}
135144
}

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Internal/BindingContextMemberProvider.cs

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -63,40 +63,49 @@ private static bool TryGetFieldHashCode(Type contextType, FieldInfo fieldInfo, o
6363
return TryGetHashCode(contextType, fieldInfo.Name, fieldInfo.FieldType, out hashCode);
6464
}
6565

66-
if (TryGetPropertyNameFromAttribute(fieldInfo, out var fieldName))
66+
if (HasObservableAttribute(fieldInfo, out var propertyName) == false)
6767
{
68-
return TryGetHashCode(contextType, fieldName, fieldInfo.FieldType, out hashCode);
68+
hashCode = default;
69+
return false;
6970
}
7071

71-
fieldName = fieldInfo.Name;
72+
return string.IsNullOrWhiteSpace(propertyName)
73+
? TryGetHashCode(contextType, GetFieldName(fieldInfo.Name), fieldInfo.FieldType, out hashCode)
74+
: TryGetHashCode(contextType, propertyName, fieldInfo.FieldType, out hashCode);
75+
}
7276

73-
if (fieldName.Length > 1)
77+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
78+
private static bool TryGetPropertyHashCode(Type contextType, PropertyInfo propertyInfo, out int hashCode)
79+
{
80+
if (propertyInfo.GetMethod.IsPrivate)
7481
{
75-
if (fieldName[0] == '_')
76-
{
77-
fieldName = fieldName[1..]; // TODO: Get rid of allocation.
78-
}
79-
80-
if (fieldName[0] == 'm' && fieldName[1] == '_')
81-
{
82-
fieldName = fieldName[2..]; // TODO: Get rid of allocation.
83-
}
82+
hashCode = default;
83+
return false;
8484
}
8585

86-
if (string.IsNullOrEmpty(fieldName))
86+
return TryGetHashCode(contextType, propertyInfo.Name, propertyInfo.PropertyType, out hashCode);
87+
}
88+
89+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
90+
private static bool TryGetHashCode(Type contextType, string memberName, Type memberType, out int hashCode)
91+
{
92+
if (typeof(IBaseCommand).IsAssignableFrom(memberType) ||
93+
typeof(IBaseProperty).IsAssignableFrom(memberType))
8794
{
88-
throw new InvalidOperationException($"Field name '{fieldName}' is not supported.");
95+
hashCode = HashCodeHelper.GetMemberHashCode(contextType, memberName);
96+
return true;
8997
}
9098

91-
return TryGetHashCode(contextType, fieldName, fieldInfo.FieldType, out hashCode);
99+
hashCode = default;
100+
return false;
92101
}
93102

94103
[MethodImpl(MethodImplOptions.AggressiveInlining)]
95-
private static bool TryGetPropertyNameFromAttribute(MemberInfo fieldInfo, out string propertyName)
104+
private static bool HasObservableAttribute(MemberInfo fieldInfo, out string propertyName)
96105
{
97106
var observableAttribute = fieldInfo.GetCustomAttribute<ObservableAttribute>();
98107

99-
if (observableAttribute == null || string.IsNullOrWhiteSpace(observableAttribute.PropertyName))
108+
if (observableAttribute == null)
100109
{
101110
propertyName = default;
102111
return false;
@@ -107,29 +116,29 @@ private static bool TryGetPropertyNameFromAttribute(MemberInfo fieldInfo, out st
107116
}
108117

109118
[MethodImpl(MethodImplOptions.AggressiveInlining)]
110-
private static bool TryGetPropertyHashCode(Type contextType, PropertyInfo propertyInfo, out int hashCode)
119+
private static string GetFieldName(string fieldName)
111120
{
112-
if (propertyInfo.GetMethod.IsPrivate)
121+
var resultName = fieldName;
122+
123+
if (resultName.Length > 1)
113124
{
114-
hashCode = default;
115-
return false;
116-
}
125+
if (resultName[0] == '_')
126+
{
127+
resultName = resultName[1..]; // TODO: Get rid of allocation.
128+
}
117129

118-
return TryGetHashCode(contextType, propertyInfo.Name, propertyInfo.PropertyType, out hashCode);
119-
}
130+
if (resultName[0] == 'm' && resultName[1] == '_')
131+
{
132+
resultName = resultName[2..]; // TODO: Get rid of allocation.
133+
}
134+
}
120135

121-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
122-
private static bool TryGetHashCode(Type contextType, string memberName, Type memberType, out int hashCode)
123-
{
124-
if (typeof(IBaseCommand).IsAssignableFrom(memberType) ||
125-
typeof(IBaseProperty).IsAssignableFrom(memberType))
136+
if (string.IsNullOrEmpty(resultName))
126137
{
127-
hashCode = HashCodeHelper.GetMemberHashCode(contextType, memberName);
128-
return true;
138+
throw new InvalidOperationException($"Field name '{resultName}' is not supported.");
129139
}
130140

131-
hashCode = default;
132-
return false;
141+
return resultName;
133142
}
134143
}
135144
}

tests/UnityMvvmToolkit.Test.Integration/TestBindingContext/MyBindingContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace UnityMvvmToolkit.Test.Integration.TestBindingContext;
1010

1111
public class MyBindingContext : IBindingContext
1212
{
13+
[Observable]
1314
private readonly IProperty<int> _count = new Property<int>();
1415

1516
[Observable(nameof(IntReadOnlyValue))]

tests/UnityMvvmToolkit.Test.Unit/BindingContextMemberProviderTests.cs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public void GetBindingContextMembers_ShouldThrow_WhenTypeIsNotAssignableFromIBin
111111
public void GetBindingContextMembers_ShouldThrow_WhenResultsDictionaryIsNull()
112112
{
113113
// Arrange
114-
var bindingContextType = typeof(PrivateFieldBindingContext);
114+
var bindingContextType = typeof(ObservableFieldBindingContext);
115115

116116
// Assert
117117
_memberProvider
@@ -126,6 +126,7 @@ private static IEnumerable<object[]> BindingContextDataSets()
126126
yield return GetObservableFieldBindingContextTestData();
127127
yield return GetPublicFieldBindingContextTestData();
128128
yield return GetPrivatePropertyBindingContextTestData();
129+
yield return GetSameFieldAndPropertyNamesBindingContextTestData();
129130
yield return GetPublicPropertyBindingContextTestData();
130131
yield return GetCommandBindingContextTestData();
131132
yield return GetNoObservableFieldsBindingContextTestData();
@@ -134,17 +135,7 @@ private static IEnumerable<object[]> BindingContextDataSets()
134135
private static object[] GetPrivateFieldBindingContextTestData()
135136
{
136137
var bindingContextType = typeof(PrivateFieldBindingContext);
137-
return new object[]
138-
{
139-
bindingContextType,
140-
new (int, MemberTypes)[]
141-
{
142-
(HashCodeHelper.GetMemberHashCode(bindingContextType, "BoolField"), MemberTypes.Field),
143-
(HashCodeHelper.GetMemberHashCode(bindingContextType, "IntField"), MemberTypes.Field),
144-
(HashCodeHelper.GetMemberHashCode(bindingContextType, "FloatField"), MemberTypes.Field),
145-
(HashCodeHelper.GetMemberHashCode(bindingContextType, "StrField"), MemberTypes.Field)
146-
}
147-
};
138+
return new object[] { bindingContextType, Array.Empty<(int, MemberTypes)>() };
148139
}
149140

150141
private static object[] GetObservableFieldBindingContextTestData()
@@ -186,6 +177,20 @@ private static object[] GetPrivatePropertyBindingContextTestData()
186177
return new object[] { typeof(PrivatePropertyBindingContext), Array.Empty<(int, MemberTypes)>() };
187178
}
188179

180+
private static object[] GetSameFieldAndPropertyNamesBindingContextTestData()
181+
{
182+
var bindingContextType = typeof(SameFieldAndPropertyNamesBindingContext);
183+
return new object[]
184+
{
185+
bindingContextType,
186+
new (int, MemberTypes)[]
187+
{
188+
(HashCodeHelper.GetMemberHashCode(bindingContextType, nameof(SameFieldAndPropertyNamesBindingContext.Count)),
189+
MemberTypes.Property)
190+
}
191+
};
192+
}
193+
189194
private static object[] GetPublicPropertyBindingContextTestData()
190195
{
191196
var bindingContextType = typeof(PublicPropertyBindingContext);

tests/UnityMvvmToolkit.Test.Unit/TestBindingContext/InvalidFieldNameBindingContext.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using UnityMvvmToolkit.Core;
2+
using UnityMvvmToolkit.Core.Attributes;
23
using UnityMvvmToolkit.Core.Interfaces;
34

45
// ReSharper disable UnusedMember.Local
@@ -8,6 +9,9 @@ namespace UnityMvvmToolkit.Test.Unit.TestBindingContext;
89

910
public class InvalidFieldNameBindingContext : IBindingContext
1011
{
12+
[Observable]
1113
private IProperty<int> _ = new Property<int>();
14+
15+
[Observable]
1216
private IProperty<int> m_ = new Property<int>();
1317
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using UnityMvvmToolkit.Core;
2+
using UnityMvvmToolkit.Core.Interfaces;
3+
4+
namespace UnityMvvmToolkit.Test.Unit.TestBindingContext;
5+
6+
public class SameFieldAndPropertyNamesBindingContext : IBindingContext
7+
{
8+
private readonly IProperty<int> _count = new Property<int>();
9+
10+
public IReadOnlyProperty<int> Count => _count;
11+
}

0 commit comments

Comments
 (0)