🔹 1. Quelle est la différence entre Equals() et == en C# ?
✅ == :
-
Par défaut, pour les types référence, compare les références mémoire (identité des objets).
-
Pour les types valeur (structs), compare les valeurs champ par champ.
-
Peut être surchargé (operator overloading) pour changer le comportement.
✅ Equals() :
-
Méthode virtuelle héritée de
System.Object. -
Sert à comparer le contenu logique (valeur) d’un objet.
-
Peut être redéfinie (
override) pour personnaliser la logique d’égalité.
Exemple :
string s1 = new string("Hello".ToCharArray());
string s2 = new string("Hello".ToCharArray());
Console.WriteLine(s1 == s2); // True -> opérateur surchargé dans System.String
Console.WriteLine(s1.Equals(s2)); // True -> compare le contenu
Console.WriteLine(ReferenceEquals(s1, s2)); // False -> pas la même instance
🧠 Résumé :
==→ peut comparer références ou valeurs selon le type.
Equals()→ compare le contenu logique (souvent redéfini).
ReferenceEquals()→ compare les adresses mémoire uniquement.
🔹 2. Pourquoi doit-on redéfinir GetHashCode() lorsqu'on redéfinit Equals() ?
Parce que les deux méthodes doivent rester cohérentes entre elles.
✅ Contrat fondamental (défini par .NET) :
-
Si
a.Equals(b)esttrue, alorsa.GetHashCode()doit être égal àb.GetHashCode(). -
Si
a.Equals(b)estfalse, leurs hashcodes peuvent être différents (mais pas obligatoire). -
Les hashcodes sont utilisés dans les collections basées sur le hachage (
Dictionary,HashSet, etc.).
Exemple :
var set = new HashSet<Person>();
set.Add(new Person("John", 30));
set.Add(new Person("John", 30)); // doublon ? dépend de Equals/GetHashCode
➡️ Si GetHashCode() n’est pas redéfini, ces deux objets auront des hashcodes différents et seront traités comme distincts, même si Equals retourne true.
🧠 En résumé :
Toujours redéfinir
GetHashCode()dès queEquals()est redéfini.
🔹 3. Donnez un exemple de redéfinition correcte des méthodes Equals() et GetHashCode().
Exemple complet :
public class Person
{
public string Name { get; }
public int Age { get; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
public override bool Equals(object obj)
{
if (obj is Person other)
return Name == other.Name && Age == other.Age;
return false;
}
public override int GetHashCode()
{
// Combiner les hashcodes des propriétés significatives
return HashCode.Combine(Name, Age);
}
public override string ToString() => $"{Name} ({Age})";
}
Utilisation :
var p1 = new Person("Alice", 25);
var p2 = new Person("Alice", 25);
Console.WriteLine(p1.Equals(p2)); // True
Console.WriteLine(p1.GetHashCode() == p2.GetHashCode()); // True
✅ Ici :
-
Equals()compare la logique métier (nom + âge). -
GetHashCode()garantit la cohérence pour les collections de hachage.
🔹 4. Comment comparer des objets en tenant compte de leurs références et de leurs valeurs ?
| Objectif | Méthode à utiliser | Description |
|---|---|---|
| Comparer les références | ReferenceEquals(a, b) |
Vérifie si les deux variables pointent vers la même instance. |
| Comparer les valeurs | a.Equals(b) ou == (si surchargé) |
Vérifie si les objets sont logiquement équivalents. |
Exemple :
var a = new Person("Bob", 40);
var b = new Person("Bob", 40);
var c = a;
Console.WriteLine(ReferenceEquals(a, b)); // False (instances différentes)
Console.WriteLine(ReferenceEquals(a, c)); // True (même instance)
Console.WriteLine(a.Equals(b)); // True (même contenu)
🧠 En résumé :
ReferenceEquals→ identité.
Equals→ égalité logique.
==→ selon implémentation.
🔹 5. Pourquoi String.Equals est-il préféré à == pour la comparaison de chaînes ?
Même si == est surchargé dans System.String pour comparer les valeurs, String.Equals offre :
-
Plus de contrôle via des options (
StringComparison). -
Une meilleure lisibilité et robustesse dans les comparaisons culturelles.
-
Moins d’ambiguïté (évite les comportements inattendus dans certaines cultures ou localisations).
Exemple :
string s1 = "résumé";
string s2 = "RESUMÉ";
// Comparaison insensible à la casse et à la culture
bool equal = string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase);
Console.WriteLine(equal); // True
🧠 Résumé :
Utilisez
String.Equals(a, b, StringComparison.OrdinalIgnoreCase)pour une comparaison explicite et fiable, surtout dans les applications globalisées.
🔹 6. Qu'est-ce que l’interface IEquatable<T> et pourquoi est-elle utile ?
✅ Définition :
IEquatable<T> fournit une méthode typée Equals(T other) pour comparer des objets sans passer par object.
public interface IEquatable<T>
{
bool Equals(T other);
}
✅ Avantages :
-
Performance : évite le boxing/unboxing (notamment pour les structs).
-
Cohérence : utilisée par les collections génériques (
List<T>.Contains,Dictionary, etc.). -
Type safety : pas besoin de caster en
object.
Exemple :
public class Person : IEquatable<Person>
{
public string Name { get; set; }
public bool Equals(Person other)
{
if (other is null) return false;
return Name == other.Name;
}
public override bool Equals(object obj) => Equals(obj as Person);
public override int GetHashCode() => Name?.GetHashCode() ?? 0;
}
Utilisation :
var p1 = new Person { Name = "Tom" };
var p2 = new Person { Name = "Tom" };
Console.WriteLine(p1.Equals(p2)); // True
🧠 En résumé :
Implémentez
IEquatable<T>pour des comparaisons rapides, typées et cohérentes dans les collections génériques.
📘 Récapitulatif synthétique
| Concept | Description | Exemple clé |
|---|---|---|
== |
Compare références ou valeurs selon le type | a == b |
Equals() |
Compare la valeur logique | a.Equals(b) |
GetHashCode() |
Doit être cohérent avec Equals() |
HashCode.Combine(...) |
ReferenceEquals() |
Compare les références mémoire | ReferenceEquals(a, b) |
String.Equals() |
Comparaison de chaînes robuste | String.Equals(a, b, StringComparison.Ordinal) |
IEquatable<T> |
Comparaison typée et performante | class MyType : IEquatable<MyType> |
🔹 1. Quelle est la différence entre deep copy et shallow copy en C# ?
✅ Shallow Copy (copie superficielle)
-
Copie uniquement les champs de premier niveau (valeurs primitives).
-
Les objets référencés sont partagés entre la source et la copie → ils pointent vers la même instance.
class Person
{
public string Name;
public Address Addr;
public Person ShallowCopy() => (Person)this.MemberwiseClone();
}
class Address { public string City; }
var p1 = new Person { Name = "John", Addr = new Address { City = "Paris" } };
var p2 = p1.ShallowCopy();
p2.Addr.City = "Lyon"; // ❌ Modifie aussi p1.Addr.City (référence partagée)
✅ Deep Copy (copie profonde)
-
Crée une nouvelle instance complète, y compris pour les objets imbriqués.
-
Les modifications sur la copie n’affectent pas l’original.
public Person DeepCopy() =>
new Person
{
Name = this.Name,
Addr = new Address { City = this.Addr.City }
};
🧠 Résumé :
Shallow = copie d’adresse,
Deep = duplication complète d’objet.
🔹 2. Comment implémenter correctement IComparable dans une classe personnalisée ?
✅ But :
Permet de définir un ordre naturel pour vos objets (tri, recherche, etc.).
🧩 Exemple :
public class Employee : IComparable<Employee>
{
public int Id { get; set; }
public string Name { get; set; }
public int CompareTo(Employee other)
{
if (other == null) return 1;
return this.Id.CompareTo(other.Id); // Tri par Id
}
}
🧠 Bonnes pratiques :
-
Retourner :
-
0si égalité -
> 0si l’objet courant est “plus grand” -
< 0sinon
-
-
Compatible avec
List<T>.Sort(),Array.Sort()etLINQ OrderBy.
🔹 3. Pourquoi utiliser StringComparison.OrdinalIgnoreCase pour comparer des chaînes de caractères ?
✅ Objectif :
Comparer deux chaînes sans tenir compte de la casse (a == A) et de manière performante.
🧩 Exemple :
bool result = string.Equals("HELLO", "hello", StringComparison.OrdinalIgnoreCase); // true
⚙️ Comparaisons possibles :
-
Ordinal→ compare les valeurs Unicode, rapide et déterministe. -
CurrentCultureIgnoreCase→ sensible à la culture locale (moins performant, plus complexe).
🧠 Résumé :
Utiliser
OrdinalIgnoreCasepour les comparaisons techniques (fichiers, clés, IDs),
CurrentCultureIgnoreCasepour le texte destiné à l’utilisateur.
🔹 4. Comment fonctionne l’opérateur ?? (null-coalescing) et ?. (null-conditional) ?
✅ ?? — Null-coalescing
Retourne la valeur de droite si celle de gauche est null :
string name = user.Name ?? "Inconnu";
✅ ?. — Null-conditional
Évite les exceptions NullReferenceException :
string city = user?.Address?.City;
🧠 Résumé :
?.: arrêt sûr si null (propage null)
??: fournit une valeur par défaut.
🔹 5. Quelle est la différence entre ReferenceEquals() et Equals() ?
| Méthode | Description | Utilisation |
|---|---|---|
ReferenceEquals(a, b) |
Compare les adresses mémoire | Teste si les deux références pointent vers le même objet |
Equals(a, b) |
Compare les valeurs si redéfinie | Peut être surchargée pour tester l’égalité logique |
🧩 Exemple :
var p1 = new Person { Name = "John" };
var p2 = new Person { Name = "John" };
Console.WriteLine(ReferenceEquals(p1, p2)); // false
Console.WriteLine(p1.Equals(p2)); // true si Equals est redéfini
🧠 Résumé :
ReferenceEquals= même instance
Equals= mêmes valeurs (logiquement équivalentes)
🔹 6. Pourquoi faut-il utiliser StringBuilder au lieu de string pour les manipulations de texte intensives ?
✅ Caractéristique de string :
-
stringest immutable → chaque concaténation crée un nouvel objet. -
En boucle, cela génère des allocations mémoire coûteuses.
✅ StringBuilder :
-
Mutable, construit la chaîne en mémoire sans recréer des objets à chaque étape.
🧩 Exemple :
var sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
sb.Append("Hello");
string result = sb.ToString();
🧠 Résumé :
StringBuilder= plus performant pour concaténations répétées ou gros volumes de texte.
🔹 7. Quelle est la différence entre object.Equals(a, b) et a.Equals(b) ?
| Méthode | Description | Avantage |
|---|---|---|
object.Equals(a, b) |
Gère automatiquement les cas où a ou b sont null |
Évite NullReferenceException |
a.Equals(b) |
Appelle la méthode Equals de l’objet a |
Nécessite que a ne soit pas null |
🧩 Exemple :
object a = null;
object b = null;
Console.WriteLine(object.Equals(a, b)); // ✅ true
Console.WriteLine(a.Equals(b)); // ❌ NullReferenceException
🧠 Résumé :
Toujours préférer
object.Equals(a, b)si on n’est pas sûr queasoit non-null.
🔹 8. Pourquoi l’interface IEqualityComparer est-elle utile et comment l’implémenter ?
✅ Objectif :
Permet de personnaliser la logique de comparaison et de hachage d’objets dans les collections (Dictionary, HashSet…).
🧩 Exemple :
Comparer des personnes sans tenir compte de la casse :
public class PersonComparer : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y) =>
string.Equals(x?.Name, y?.Name, StringComparison.OrdinalIgnoreCase);
public int GetHashCode(Person obj) =>
obj.Name?.ToLowerInvariant().GetHashCode() ?? 0;
}
var people = new HashSet<Person>(new PersonComparer());
🧠 Résumé :
IEqualityComparer<T>permet d’avoir plusieurs stratégies d’égalité pour une même classe.
🔹 9. Comment empêcher la modification d’un objet après son instanciation (pattern immuable) ?
✅ But :
Créer des objets immutables (non modifiables après création).
→ Sécurité, thread-safety, prévisibilité.
🧩 Exemple :
public class User
{
public string Name { get; }
public int Age { get; }
public User(string name, int age)
{
Name = name;
Age = age;
}
public User WithAge(int newAge) => new User(Name, newAge);
}
🧠 Bonnes pratiques :
-
Utiliser des propriétés en lecture seule
-
Pas de setters publics
-
Fournir des méthodes “WithX()” pour créer de nouvelles versions
🔹 10. Comment comparer deux collections d’objets en C# ?
✅ Plusieurs options :
🔸 a) Comparaison séquentielle (ordre important)
bool equal = list1.SequenceEqual(list2);
🔸 b) Comparaison sans ordre :
bool equal = list1.OrderBy(x => x).SequenceEqual(list2.OrderBy(x => x));
🔸 c) Comparaison avec logique personnalisée :
bool equal = list1.SequenceEqual(list2, new PersonComparer());
🧠 Résumé :
SequenceEqual()→ parfait pour comparer des séquences
IEqualityComparer<T>→ utile pour définir les critères de comparaison personnalisés.
📘 RÉCAPITULATIF SYNTHÉTIQUE
| Thème | Objectif | Exemple clé |
|---|---|---|
| Deep vs Shallow Copy | Contrôle du clonage d’objets | MemberwiseClone() vs duplication complète |
| IComparable | Tri naturel d’objets | CompareTo() |
| StringComparison | Comparaison optimisée de chaînes | OrdinalIgnoreCase |
?? et ?. |
Gestion du null élégante |
user?.Name ?? "N/A" |
| ReferenceEquals vs Equals | Référence vs Valeur | ReferenceEquals(a,b) |
| StringBuilder | Performance pour concaténation | sb.Append() |
| object.Equals vs a.Equals | Gestion du null | object.Equals(a,b) |
| IEqualityComparer | Comparaison personnalisée | HashSet<Person>(new PersonComparer()) |
| Objet immuable | Sécurité et thread-safety | readonly properties |
| Comparer collections | Égalité de séquences | SequenceEqual() |
Aucun commentaire:
Enregistrer un commentaire