Open sandboxFocusImprove this doc

LAMA5166: A property of a base type can't be observed

Severity Warning
Reported by Metalama.Patterns.Observability
Message The '<Property>' property cannot be observed because '<DeclaringType>' does not implement INotifyPropertyChanged. Consider implementing the INotifyPropertyChanged interface in '<DeclaringType>', marking '<DeclaringType>' with [Constant], or using ConfigureObservability via a fabric.

Cause

The [Observable] aspect updates a computed property when the properties it depends on change. For a property of a base type, the aspect relies on the base type raising the PropertyChanged event.

Metalama reports LAMA5166 when a computed property of an observable type reads a property of a base class that doesn't implement INotifyPropertyChanged. In the message, <Property> is the property of the base type and <DeclaringType> is the base type. The aspect can't detect changes to this property, so the computed property isn't notified.

If a computed property reads a child of another computed property of the same type, Metalama reports LAMA5163 instead.

In the following example, Greeting reads FirstName, a property of the Person base class that isn't observable.

Source Code
1using Metalama.Patterns.Observability;
2

3namespace Doc.LAMA5166.Error;
4
5// This base class does not implement INotifyPropertyChanged.
6public class Person
7{
8    public string FirstName { get; set; } = "";
9}
10
11[Observable]
12public partial class Employee : Person
13{
14    // Warning: changes to FirstName cannot be observed.
    Warning LAMA5166: The 'Person.FirstName' property cannot be observed because 'Person' does not implement INotifyPropertyChanged. Consider implementing the INotifyPropertyChanged interface in 'Person', marking 'Person' with [Constant], or using ConfigureObservability via a fabric.

15    public string Greeting => "Hello, " + this.FirstName;
16}
17
Transformed Code
1using System.ComponentModel;
2using Metalama.Patterns.Observability;
3
4namespace Doc.LAMA5166.Error;
5
6// This base class does not implement INotifyPropertyChanged.
7public class Person
8{
9    public string FirstName { get; set; } = "";
10}
11
12[Observable]
13public partial class Employee : Person, INotifyPropertyChanged
14{
15    // Warning: changes to FirstName cannot be observed.
16    public string Greeting => "Hello, " + this.FirstName;
17
18    protected virtual void OnPropertyChanged(string propertyName)
19    {
20        switch (propertyName)
21        {
22            case "FirstName":
23                OnPropertyChanged("Greeting");
24                break;
25        }
26
27        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
28    }
29
30    public event PropertyChangedEventHandler? PropertyChanged;
31}
32

Resolution

Do one of the following:

  • Apply the [Observable] aspect to the base type, as in the following example, or implement INotifyPropertyChanged in it manually.
  • If you cannot change the base type, follow the other suggestions of the message: mark the property as constant, or configure the observability of the property with ConfigureObservability in a fabric.

Source Code
1using Metalama.Patterns.Observability;
2

3namespace Doc.LAMA5166.Fixed;
4
5// Fixed: the base class is observable.
6[Observable]
7public partial class Person
8{
9    public string FirstName { get; set; } = "";
10}





















11



12[Observable]
13public partial class Employee : Person
14{
15    public string Greeting => "Hello, " + this.FirstName;
16}
17
Transformed Code
1using System.ComponentModel;
2using Metalama.Patterns.Observability;
3
4namespace Doc.LAMA5166.Fixed;
5
6// Fixed: the base class is observable.
7[Observable]
8public partial class Person : INotifyPropertyChanged
9{
10    private string _firstName = "";
11
12    public string FirstName
13    {
14        get
15        {
16            return _firstName;
17        }
18
19        set
20        {
21            if (!object.ReferenceEquals(value, _firstName))
22            {
23                _firstName = value;
24                OnPropertyChanged("FirstName");
25            }
26        }
27    }
28
29    protected virtual void OnPropertyChanged(string propertyName)
30    {
31        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
32    }
33
34    public event PropertyChangedEventHandler? PropertyChanged;
35}
36
37[Observable]
38public partial class Employee : Person
39{
40    public string Greeting => "Hello, " + this.FirstName;
41
42    protected override void OnPropertyChanged(string propertyName)
43    {
44        switch (propertyName)
45        {
46            case "FirstName":
47                OnPropertyChanged("Greeting");
48                break;
49        }
50
51        base.OnPropertyChanged(propertyName);
52    }
53}
54

See also