Skip to content

Commit 2b3c84e

Browse files
committed
Add ObservableAttribute.
1 parent 68de030 commit 2b3c84e

6 files changed

Lines changed: 141 additions & 10 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
3+
namespace System.Runtime.CompilerServices
4+
{
5+
internal static class IsExternalInit {}
6+
}
7+
8+
namespace UnityMvvmToolkit.Core.Attributes
9+
{
10+
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
11+
public sealed class ObservableAttribute : Attribute
12+
{
13+
/// <summary>
14+
/// If PropertyName is not specified, the field name will be converted from '_name' or 'm_name' to 'Name'.
15+
/// </summary>
16+
/// <param name="propertyName">Property name to bind.</param>
17+
public ObservableAttribute(string propertyName = "")
18+
{
19+
PropertyName = propertyName;
20+
}
21+
22+
public string PropertyName { get; init; }
23+
}
24+
}

src/UnityMvvmToolkit.Core/Internal/BindingContextMemberProvider.cs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Reflection;
44
using System.Runtime.CompilerServices;
5+
using UnityMvvmToolkit.Core.Attributes;
56
using UnityMvvmToolkit.Core.Interfaces;
67
using UnityMvvmToolkit.Core.Internal.Helpers;
78
using UnityMvvmToolkit.Core.Internal.Interfaces;
@@ -28,7 +29,7 @@ public void GetBindingContextMembers(Type bindingContextType, IDictionary<int, M
2829
}
2930

3031
[MethodImpl(MethodImplOptions.AggressiveInlining)]
31-
private bool TryGetMemberHashCode(Type contextType, MemberInfo memberInfo, out int hashCode)
32+
private static bool TryGetMemberHashCode(Type contextType, MemberInfo memberInfo, out int hashCode)
3233
{
3334
switch (memberInfo.MemberType)
3435
{
@@ -43,15 +44,25 @@ private bool TryGetMemberHashCode(Type contextType, MemberInfo memberInfo, out i
4344
}
4445

4546
[MethodImpl(MethodImplOptions.AggressiveInlining)]
46-
private bool TryGetFieldHashCode(Type contextType, FieldInfo fieldInfo, out int hashCode)
47+
private static bool TryGetFieldHashCode(Type contextType, FieldInfo fieldInfo, out int hashCode)
4748
{
4849
if (fieldInfo.IsDefined(typeof(CompilerGeneratedAttribute), false))
4950
{
5051
hashCode = default;
5152
return false;
5253
}
5354

54-
var fieldName = fieldInfo.Name;
55+
if (fieldInfo.IsPublic)
56+
{
57+
return TryGetHashCode(contextType, fieldInfo.Name, fieldInfo.FieldType.GetInterfaces(), out hashCode);
58+
}
59+
60+
if (TryGetPropertyNameFromAttribute(fieldInfo, out var fieldName))
61+
{
62+
return TryGetHashCode(contextType, fieldName, fieldInfo.FieldType.GetInterfaces(), out hashCode);
63+
}
64+
65+
fieldName = fieldInfo.Name;
5566

5667
if (fieldName.Length > 1)
5768
{
@@ -66,18 +77,39 @@ private bool TryGetFieldHashCode(Type contextType, FieldInfo fieldInfo, out int
6677
}
6778
}
6879

80+
if (string.IsNullOrEmpty(fieldName))
81+
{
82+
throw new InvalidOperationException($"Field name '{fieldName}' is not supported.");
83+
}
84+
6985
return TryGetHashCode(contextType, fieldName, fieldInfo.FieldType.GetInterfaces(), out hashCode);
7086
}
7187

7288
[MethodImpl(MethodImplOptions.AggressiveInlining)]
73-
private bool TryGetPropertyHashCode(Type contextType, PropertyInfo propertyInfo, out int hashCode)
89+
private static bool TryGetPropertyNameFromAttribute(MemberInfo fieldInfo, out string propertyName)
90+
{
91+
var observableAttribute = fieldInfo.GetCustomAttribute<ObservableAttribute>();
92+
93+
if (observableAttribute == null || string.IsNullOrWhiteSpace(observableAttribute.PropertyName))
94+
{
95+
propertyName = default;
96+
return false;
97+
}
98+
99+
propertyName = observableAttribute.PropertyName;
100+
return true;
101+
}
102+
103+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
104+
private static bool TryGetPropertyHashCode(Type contextType, PropertyInfo propertyInfo, out int hashCode)
74105
{
75106
return TryGetHashCode(contextType, propertyInfo.Name, propertyInfo.PropertyType.GetInterfaces(),
76107
out hashCode);
77108
}
78109

79110
[MethodImpl(MethodImplOptions.AggressiveInlining)]
80-
private bool TryGetHashCode(Type contextType, string memberName, Type[] memberInterfaces, out int hashCode)
111+
private static bool TryGetHashCode(Type contextType, string memberName, Type[] memberInterfaces,
112+
out int hashCode)
81113
{
82114
for (var i = 0; i < memberInterfaces.Length; i++)
83115
{

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Attributes.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
3+
namespace System.Runtime.CompilerServices
4+
{
5+
internal static class IsExternalInit {}
6+
}
7+
8+
namespace UnityMvvmToolkit.Core.Attributes
9+
{
10+
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
11+
public sealed class ObservableAttribute : Attribute
12+
{
13+
/// <summary>
14+
/// If PropertyName is not specified, the field name will be converted from '_name' or 'm_name' to 'Name'.
15+
/// </summary>
16+
/// <param name="propertyName">Property name to bind.</param>
17+
public ObservableAttribute(string propertyName = "")
18+
{
19+
PropertyName = propertyName;
20+
}
21+
22+
public string PropertyName { get; init; }
23+
}
24+
}

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Core/Attributes/ObservableAttribute.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Reflection;
44
using System.Runtime.CompilerServices;
5+
using UnityMvvmToolkit.Core.Attributes;
56
using UnityMvvmToolkit.Core.Interfaces;
67
using UnityMvvmToolkit.Core.Internal.Helpers;
78
using UnityMvvmToolkit.Core.Internal.Interfaces;
@@ -28,7 +29,7 @@ public void GetBindingContextMembers(Type bindingContextType, IDictionary<int, M
2829
}
2930

3031
[MethodImpl(MethodImplOptions.AggressiveInlining)]
31-
private bool TryGetMemberHashCode(Type contextType, MemberInfo memberInfo, out int hashCode)
32+
private static bool TryGetMemberHashCode(Type contextType, MemberInfo memberInfo, out int hashCode)
3233
{
3334
switch (memberInfo.MemberType)
3435
{
@@ -43,15 +44,25 @@ private bool TryGetMemberHashCode(Type contextType, MemberInfo memberInfo, out i
4344
}
4445

4546
[MethodImpl(MethodImplOptions.AggressiveInlining)]
46-
private bool TryGetFieldHashCode(Type contextType, FieldInfo fieldInfo, out int hashCode)
47+
private static bool TryGetFieldHashCode(Type contextType, FieldInfo fieldInfo, out int hashCode)
4748
{
4849
if (fieldInfo.IsDefined(typeof(CompilerGeneratedAttribute), false))
4950
{
5051
hashCode = default;
5152
return false;
5253
}
5354

54-
var fieldName = fieldInfo.Name;
55+
if (fieldInfo.IsPublic)
56+
{
57+
return TryGetHashCode(contextType, fieldInfo.Name, fieldInfo.FieldType.GetInterfaces(), out hashCode);
58+
}
59+
60+
if (TryGetPropertyNameFromAttribute(fieldInfo, out var fieldName))
61+
{
62+
return TryGetHashCode(contextType, fieldName, fieldInfo.FieldType.GetInterfaces(), out hashCode);
63+
}
64+
65+
fieldName = fieldInfo.Name;
5566

5667
if (fieldName.Length > 1)
5768
{
@@ -66,18 +77,39 @@ private bool TryGetFieldHashCode(Type contextType, FieldInfo fieldInfo, out int
6677
}
6778
}
6879

80+
if (string.IsNullOrEmpty(fieldName))
81+
{
82+
throw new InvalidOperationException($"Field name '{fieldName}' is not supported.");
83+
}
84+
6985
return TryGetHashCode(contextType, fieldName, fieldInfo.FieldType.GetInterfaces(), out hashCode);
7086
}
7187

7288
[MethodImpl(MethodImplOptions.AggressiveInlining)]
73-
private bool TryGetPropertyHashCode(Type contextType, PropertyInfo propertyInfo, out int hashCode)
89+
private static bool TryGetPropertyNameFromAttribute(MemberInfo fieldInfo, out string propertyName)
90+
{
91+
var observableAttribute = fieldInfo.GetCustomAttribute<ObservableAttribute>();
92+
93+
if (observableAttribute == null || string.IsNullOrWhiteSpace(observableAttribute.PropertyName))
94+
{
95+
propertyName = default;
96+
return false;
97+
}
98+
99+
propertyName = observableAttribute.PropertyName;
100+
return true;
101+
}
102+
103+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
104+
private static bool TryGetPropertyHashCode(Type contextType, PropertyInfo propertyInfo, out int hashCode)
74105
{
75106
return TryGetHashCode(contextType, propertyInfo.Name, propertyInfo.PropertyType.GetInterfaces(),
76107
out hashCode);
77108
}
78109

79110
[MethodImpl(MethodImplOptions.AggressiveInlining)]
80-
private bool TryGetHashCode(Type contextType, string memberName, Type[] memberInterfaces, out int hashCode)
111+
private static bool TryGetHashCode(Type contextType, string memberName, Type[] memberInterfaces,
112+
out int hashCode)
81113
{
82114
for (var i = 0; i < memberInterfaces.Length; i++)
83115
{

0 commit comments

Comments
 (0)