• The single-responsibility principle – piece of software should have only one responsibility
  • The open–closed principle – things should be open for extension but closed for modification
  • The Liskov substitution principle – changing interface implementation should not brake software
  • The interface segregation principle – it is better to have more specialized interfaces than single big one
  • The dependency inversion principle – dependencies should be abstracted via interfaces

Further read:

.NET/C# interview questions

Equals and GetHashCode

Custom implementation is usually only necessary if default, reference equality is not enough. In example:

  • entities value based equality
  • value equality of deserialized objects
  • custom comparisons based on other criterias
public class ImaginaryNumber : IEquatable<ImaginaryNumber>
    public double RealNumber { get; set; }
    public double ImaginaryUnit { get; set; }

    public override bool Equals(object obj)
        return Equals(obj as ImaginaryNumber);

    public bool Equals(ImaginaryNumber other)
        return other != null &&
               RealNumber == other.RealNumber &&
               ImaginaryUnit == other.ImaginaryUnit;

    public override int GetHashCode()
        return HashCode.Combine(RealNumber, ImaginaryUnit);