| Severity | Warning |
| Reported by | Metalama.Patterns.Observability |
| Message | The '<Field>' field cannot be observed: only private instance fields, constants, and read-only fields of immutable types are supported. Consider replacing the field with a property, or making it private. |
Cause
The [Observable] aspect analyzes the getter of each computed property to find the fields and properties it depends on. It supports only the following fields:
- private instance fields,
- constants,
- read-only fields of an immutable type, such as
string,int, or a type marked as immutable. For details, see Metalama.Patterns.Immutability.
Metalama reports LAMA5164 when a computed property reads any other field, for example a public, protected, or internal field, or a mutable static field. Code of other classes can change such a field without raising a notification, so the computed property wouldn't be notified. In the message, <Field> is the field.
In the following example, Total reads the public field UnitPrice.
Source Code
1using Metalama.Patterns.Observability;
2
3namespace Doc.LAMA5164.Error;
4
5[Observable]
6public partial class OrderLine
7{
8 public decimal UnitPrice;
9
10 public int Quantity { get; set; }
11
12 // Warning: UnitPrice is a public field, so changes to it can't be observed.
Warning LAMA5164: The 'OrderLine.UnitPrice' field cannot be observed: only private instance fields, constants, and read-only fields of immutable types are supported. Consider replacing the field with a property, or making it private.
13 public decimal Total => this.UnitPrice * this.Quantity;
14}
15
Transformed Code
1using System.ComponentModel;
2using Metalama.Patterns.Observability;
3
4namespace Doc.LAMA5164.Error;
5
6[Observable]
7public partial class OrderLine : INotifyPropertyChanged
8{
9 private decimal _unitPrice;
10
11 public decimal UnitPrice
12 {
13 get
14 {
15 return _unitPrice;
16 }
17
18 set
19 {
20 if (_unitPrice != value)
21 {
22 _unitPrice = value;
23 }
24 }
25 }
26
27 private int _quantity;
28
29 public int Quantity
30 {
31 get
32 {
33 return _quantity;
34 }
35
36 set
37 {
38 if (_quantity != value)
39 {
40 _quantity = value;
41 OnPropertyChanged("Total");
42 OnPropertyChanged("Quantity");
43 }
44 }
45 }
46
47 // Warning: UnitPrice is a public field, so changes to it can't be observed.
48 public decimal Total => this.UnitPrice * this.Quantity;
49
50 protected virtual void OnPropertyChanged(string propertyName)
51 {
52 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
53 }
54
55 public event PropertyChangedEventHandler? PropertyChanged;
56}
57
Resolution
Do one of the following:
- Replace the field with an auto-property, as in the following example. The aspect then raises a notification when the property changes.
- Make the field
private, and expose it through a property if other classes need it. - If the field never changes, make it
readonlyorconst, provided its type is immutable.
Source Code
1using Metalama.Patterns.Observability;
2
3namespace Doc.LAMA5164.Fixed;
4
5[Observable]
6public partial class OrderLine
7{
8 // Fixed: the public field is replaced with an auto-property.
9 public decimal UnitPrice { get; set; }
10
11 public int Quantity { get; set; }
12
13 public decimal Total => this.UnitPrice * this.Quantity;
14}
15
Transformed Code
1using System.ComponentModel;
2using Metalama.Patterns.Observability;
3
4namespace Doc.LAMA5164.Fixed;
5
6[Observable]
7public partial class OrderLine : INotifyPropertyChanged
8{
9 private decimal _unitPrice;
10
11 // Fixed: the public field is replaced with an auto-property.
12 public decimal UnitPrice
13 {
14 get
15 {
16 return _unitPrice;
17 }
18
19 set
20 {
21 if (_unitPrice != value)
22 {
23 _unitPrice = value;
24 OnPropertyChanged("Total");
25 OnPropertyChanged("UnitPrice");
26 }
27 }
28 }
29
30 private int _quantity;
31
32 public int Quantity
33 {
34 get
35 {
36 return _quantity;
37 }
38
39 set
40 {
41 if (_quantity != value)
42 {
43 _quantity = value;
44 OnPropertyChanged("Total");
45 OnPropertyChanged("Quantity");
46 }
47 }
48 }
49
50 public decimal Total => this.UnitPrice * this.Quantity;
51
52 protected virtual void OnPropertyChanged(string propertyName)
53 {
54 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
55 }
56
57 public event PropertyChangedEventHandler? PropertyChanged;
58}
59