1
+ < p > A < code > class</ code > with only < code > abstract</ code > methods and no inheritable behavior should be converted to an < a
2
+ href ="https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ "> < code > interface</ code > </ a > .</ p >
1
3
< h2 > Why is this an issue?</ h2 >
2
- < p > The purpose of an abstract class is to provide some heritable behaviors while also defining methods which must be implemented by sub-classes.</ p >
3
- < p > A < code > class</ code > with only < code > abstract</ code > methods and no inheritable behavior should be converted to an < code > interface</ code > .</ p >
4
- < h3 > Noncompliant code example</ h3 >
4
+ < p > The purpose of an < a
5
+ href ="https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members "> < code > abstract</ code >
6
+ class</ a > is to provide some overridable behaviors while also defining methods that are required to be implemented by sub-classes.</ p >
7
+ < p > A class that contains only < code > abstract</ code > methods, often called pure abstract class, is effectively an interface, but with the disadvantage
8
+ of not being able to be implemented by multiple classes.</ p >
9
+ < p > Using interfaces over pure abstract classes presents multiple advantages:</ p >
10
+ < ul >
11
+ < li > < a href ="https://en.wikipedia.org/wiki/Multiple_inheritance "> < strong > Multiple Inheritance</ strong > </ a > : Unlike classes, an interface doesn’t
12
+ count towards the single inheritance limit in C#. This means a class can implement multiple interfaces, which can be useful when you need to define
13
+ behavior that can be shared across multiple classes. </ li >
14
+ < li > < a href ="https://en.wikipedia.org/wiki/Loose_coupling#In_programming "> < strong > Loose Coupling</ strong > </ a > : Interfaces provide a way to achieve
15
+ loose coupling between classes. This is because an interface only specifies what methods a class must have, but not how they are implemented. This
16
+ makes it easier to swap out implementations without changing the code that uses them. </ li >
17
+ < li > < a href ="https://en.wikipedia.org/wiki/Polymorphism_(computer_science) "> < strong > Polymorphism</ strong > </ a > : Interfaces allow you to use
18
+ polymorphism, which means you can use an interface type to refer to any object that implements that interface. This can be useful when you want to
19
+ write code that can work with any class that implements a certain interface, < em > without knowing what the actual class is</ em > . </ li >
20
+ < li > < a href ="https://en.wikipedia.org/wiki/Design_by_contract "> < strong > Design by contract</ strong > </ a > : Interfaces provide a clear contract of what
21
+ a class should do, without specifying how it should do it. This makes it easier to understand the intended behavior of a class, and to ensure that
22
+ different implementations of an interface are consistent with each other. </ li >
23
+ </ ul >
24
+ < h3 > Exceptions</ h3 >
25
+ < p > < code > abstract</ code > classes that contain non-abstract methods, in addition to < code > abstract</ code > ones, cannot easily be converted to
26
+ interfaces, and are not the subject of this rule:</ p >
5
27
< pre >
6
- public abstract class Animal // Noncompliant; should be an interface
7
- {
8
- abstract void Move();
9
- abstract void Feed();
10
- }
11
- </ pre >
12
- < h3 > Compliant solution</ h3 >
13
- < pre >
14
- public interface Animal
15
- {
16
- void Move();
17
- void Feed();
18
- }
19
-
20
- public abstract class Lamp
28
+ public abstract class Lamp // Compliant: Glow is abstract, but FlipSwitch is not
21
29
{
22
30
private bool switchLamp = false;
23
31
@@ -33,4 +41,49 @@ <h3>Compliant solution</h3>
33
41
}
34
42
}
35
43
</ pre >
44
+ < p > Notice that, since C# 8.0, you can also define < a
45
+ href ="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods "> default implementations for
46
+ interface methods</ a > , which is yet another reason to prefer interfaces over abstract classes when you don’t need to provide any inheritable
47
+ behavior.</ p >
48
+ < p > However, interfaces cannot have fields (such as < code > switchLamp</ code > in the example above), and that remains true even in C# 8.0 and upwards.
49
+ This can be a valid reason to still prefer an abstract class over an interface.</ p >
50
+ < h2 > How to fix it</ h2 >
51
+ < p > Convert the < code > abstract</ code > class to an < code > interface</ code > with the same methods.</ p >
52
+ < h3 > Code examples</ h3 >
53
+ < h4 > Noncompliant code example</ h4 >
54
+ < pre data-diff-id ="1 " data-diff-type ="noncompliant ">
55
+ public abstract class Animal // Noncompliant: should be an interface
56
+ {
57
+ public abstract void Move();
58
+ public abstract void Feed();
59
+ }
60
+ </ pre >
61
+ < h3 > Compliant solution</ h3 >
62
+ < pre data-diff-id ="1 " data-diff-type ="compliant ">
63
+ public interface Animal
64
+ {
65
+ void Move();
66
+ void Feed();
67
+ }
68
+ </ pre >
69
+ < h2 > Resources</ h2 >
70
+ < h3 > Documentation</ h3 >
71
+ < ul >
72
+ < li > Microsoft Learn - < a
73
+ href ="https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members "> Abstract
74
+ and Sealed Classes and Class Members (C# Programming Guide)</ a > </ li >
75
+ < li > Microsoft Learn - < a href ="https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ "> Interfaces - define behavior for
76
+ multiple types</ a > </ li >
77
+ < li > Microsoft Learn - < a href ="https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/default-interface-methods "> Default
78
+ Interface Methods</ a > </ li >
79
+ < li > Microsoft Learn - < a
80
+ href ="https://learn.microsoft.com/en-us/dotnet/csharp/advanced-topics/interface-implementation/default-interface-methods-versions "> Tutorial: Update
81
+ interfaces with default interface methods</ a > </ li >
82
+ < li > Microsoft Learn - < a href ="https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/inheritance "> Inheritance - derive types
83
+ to create more specialized behavior</ a > </ li >
84
+ < li > Wikipedia - < a href ="https://en.wikipedia.org/wiki/Multiple_inheritance "> Multiple Inheritance</ a > </ li >
85
+ < li > Wikipedia - < a href ="https://en.wikipedia.org/wiki/Loose_coupling#In_programming "> Loose Coupling - In programming</ a > </ li >
86
+ < li > Wikipedia - < a href ="https://en.wikipedia.org/wiki/Polymorphism_(computer_science) "> Polymorphism (computer science)</ a > </ li >
87
+ < li > Wikipedia - < a href ="https://en.wikipedia.org/wiki/Design_by_contract "> Design by contract</ a > </ li >
88
+ </ ul >
36
89
0 commit comments