0

I'm trying to understand how the elementary class structural metrics, such as ATFD (access to foreign data) and LCOM (lack of cohesion in methods) are calculated in light of C# Properties.

If a method access a single property of another class, does that mean that the ATFD score of that method is 1? Does this change based on whether there is a backing private field or not?

For LCOM, does the property count as a field or as a method (or as both) when following the formula laid out by NDepend for example https://www.ndepend.com/docs/code-metrics#LCOM.

How does this change when we have an explicit private field related to the property - i.e., what is the LCOM difference for the following classes A and C:

   class A {
      private int _b;
      private int _bx;
      public int B { get { return this._b; }
         set { this._b = value; }
      }

      public void MethodA() {
         B = 1;
      }

      public void MethodB() {
         this._bx = 1;
      }
   }

   class C {
      public int B { get; set; }
      public int Bx { get; set; }

      public void MethodA() {
         B = 1;
      }

      public void MethodB() {
         Bx = 1;
      }
   }
Patrick from NDepend team
  • 13,237
  • 6
  • 61
  • 92
NLuburić
  • 912
  • 1
  • 10
  • 28

1 Answers1

0

I modified the code in the question to make it compilable.

With NDepend, values for these 2 classes are:

class A   LCOM 0.7  LCOMHS 0.88
class C   LCOM 0.0  LCOMHS 0.0

For LCOM, does the property count as a field or as a method (or as both)

This is answered in the LCOM/LCOMHS documentation

  • LCOM = 1 – (sum(MF)/M*F)
  • LCOM HS = (M – sum(MF)/F)(M-1)

Where:

  • M is the number of methods in class (both static and instance methods are counted, it includes also constructors, properties getters/setters, events add/remove methods).
  • F is the number of instance fields in the class.
  • MF is the number of methods of the class accessing a particular instance field.
  • Sum(MF) is the sum of MF over all instance fields of the class.

Recommendations: Types where LCOM > 0.8 and NbFields > 10 and NbMethods >10 might be problematic. However, it is very hard to avoid such non-cohesive types. Types where LCOMHS > 1.0 and NbFields > 10 and NbMethods >10 should be avoided. Note that this constraint is stronger (and thus easier to satisfy) than the constraint types where LCOM > 0.8 and NbFields > 10 and NbMethods >10.


NbFields > 10 and NbMethods >10 is highlighted because LCOM / LCOMHS values are significant mostly for large and complex classes.

Patrick from NDepend team
  • 13,237
  • 6
  • 61
  • 92
  • I apologize if my math is wrong, but looking at class A I have the following numbers: M=3 (B (or does this count as 2 because of get and set?), MethA, MethB) F=2 (_b, _bx) MF=2 (B -> _b (or does this count as 2 because of get and set?), MethB -> _bx) LCOM = 1 - 2/6 = 0.67 – NLuburić Sep 29 '20 at 10:01
  • For class A M=4 because there is also the default constructor, even though it is not declared in source code. – Patrick from NDepend team Sep 30 '20 at 11:18
  • Hmm, if that is the case than M * F is 8, meaning that the end result is 1 - 2/8 = 0.75. Is it the case that B counts as 2 methods (get and set), so we have M=5, M*F=10, MF=3 (B counts as 2) and we have 1 - 3/10 = 0.7? – NLuburić Oct 01 '20 at 07:55