Abstract class vs Interface in our days

Matvey Bykovsky 36 Reputation points
2022-12-15T21:40:23.61+00:00

There are lots of answers about this question, but they are very old. Having c# 11 there are many new features with Interfaces. So, maybe someone can exactly explaine me the difference between an Abstract class and an Interface? When should i use the first one, and when the second.

Developer technologies | C#
0 comments No comments
{count} votes

Accepted answer
  1. P a u l 10,761 Reputation points
    2022-12-15T21:51:55.997+00:00

    I like to think of interfaces as contracts (this object will have property X & Y and method Z) but makes no assumptions about implementation (at least they did before Default Interface Implementations as of C# 8: https://devblogs.microsoft.com/dotnet/default-implementations-in-interfaces, although I use these sparingly if ever).

    Abstract classes (and derived non-sealed classes) can be thought of as just a place to share implementation that's common between supersets of classes and their subsets. Abstract classes provide an object-oriented way of supporting the Don't Repeat Yourself (DRY) principle (https://www.c-sharpcorner.com/article/software-design-principles-dry-kiss-yagni) where the implementation you would otherwise repeat doesn't make sense outside of the context of your class hierarchy.

    Interfaces & abstract classes are by no means mutually exclusive and can be used in conjunction with each other depending on the context.

    4 people found this answer helpful.

2 additional answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 78,086 Reputation points Volunteer Moderator
    2022-12-16T00:04:49.49+00:00

    abstract classes are to define a common base class for inheritance, without implementing any actual methods.

    because c# does not support multiple inheritance, interfaces are the solution. a class can inherit from one base class, but it can implement many interfaces. interfaces can only be implemented. an interface can not inherit from another interface.

    due to issues with inheritance chains, inheritance is often considered an anti-pattern, interface design is recommend instead. with interface design you define contacts that define properties and methods. then classes must implement. other languages use protocols/traits which are slight more feature rich than interfaces.

    one past advantage with classes, was you could define default behavior, and interfaces were abstract (no implementations). But modern C# allows default implemations for interfaces.

    so my recommendation is to avoid class inheritance (and never more than 1 deep, that is only inherit from base), but rather use interfaces and extension methods to extend classes.

    1 person found this answer helpful.
    0 comments No comments

  2. Karen Payne MVP 35,586 Reputation points Volunteer Moderator
    2022-12-15T23:36:18.203+00:00

    Adding on to what @P a u l mentioned in regards used in conjunction with each other an example for allowing overriding ToString this can not be done with an interface but can with an abstract class.

    public abstract class Human  
    {  
        public string FirstName { get; set; }  
        public string MiddleName { get; set; }  
        public string LastName { get; set; }  
        public abstract override string ToString();   
      
    }  
    

    Interface

    public interface IBase  
    {  
        public int Id { get;  }  
    }  
    

    Model

    public class Employer : Human, IBase  
    {  
        public int EmployerIdentifier { get; set; }  
        public int Id => EmployerIdentifier;  
        public override string ToString() => $"{LastName}";  
    }  
    

    Also if say some models only implement one interface and not the abstract class we can do if (person is IBase current and Human human)

    Another use is when working with generics with complex methods where in the following we constrain to a EF Core DbContext and a class which implements a specific interface. In this code we only want models from EF Core to get their navigation properties.

    public class EntityHelpers  
    {  
        public static List<NavigationItem> NavigationInformationForModel<TEntity, TContext>(string connectionString)  
            where TContext : DbContext  
            where TEntity : class,  
            IBaseEntity  
        {  
              
            var type = typeof(DbContextOptionsBuilder<>).MakeGenericType(typeof(TContext));  
            DbContextOptionsBuilder builder = (DbContextOptionsBuilder)Activator.CreateInstance(type);  
            builder!.UseSqlServer(connectionString);  
            var context = (DbContext)Activator.CreateInstance(typeof(TContext), builder.Options);  
            return context!.Model.GetEntityTypes().Where(x => x.ClrType == typeof(TEntity))  
                .Select(entityType => new NavigationItem(  
                    entityType.ClrType.Name,  
                    entityType.GetNavigations().Select(x => x.PropertyInfo)))  
                .Where(x => !x.Name.Contains("`"))  
                .ToList();  
        }  
      
      
        public static List<NavigationItem> GetNavigationInformation<TContext>(string connectionString)   
            where TContext : DbContext,   
            IBaseEntity  
        {  
      
            var type = typeof(DbContextOptionsBuilder<>).MakeGenericType(typeof(TContext));  
            DbContextOptionsBuilder builder = (DbContextOptionsBuilder)Activator.CreateInstance(type);  
            builder!.UseSqlServer(connectionString);  
            var context = (DbContext)Activator.CreateInstance(typeof(TContext), builder.Options);  
            return context!.Model.GetEntityTypes()  
                .Select(entityType => new NavigationItem(  
                    entityType.ClrType.Name,  
                    entityType.GetNavigations().Select(x => x.PropertyInfo)))  
                .Where(x => !x.Name.Contains("`"))  
                .ToList();  
        }  
    }  
    
    1 person found this answer helpful.
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.