Progettazione di buone estensioni
Applichi le best practice ed eviti le insidie.
Progettazione di buone estensioni è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 4 lezioni in totale.
Progettare metodi di estensione apprezzati dagli sviluppatori
I metodi di estensione sono potenti, ma la potenza può favorirne l'uso improprio. Le estensioni ben progettate sembrano parte naturale del tipo, sono facili da individuare e non sorprendono mai il chiamante. Questa lezione illustra alcune linee guida pratiche.
Estenda il comportamento, non l'identità
Preferisca i metodi di estensione per i comportamenti di utilità che si leggono bene in una pipeline. Se un metodo appartiene davvero a un tipo di cui si controlla il codice, lo si renda invece un membro reale.
using System;
public static class TimeExtensions
{
// A pleasant, focused helper
public static bool IsWeekend(this DayOfWeek day)
=> day == DayOfWeek.Saturday || day == DayOfWeek.Sunday;
}
public class Program
{
public static void Main()
{
Console.WriteLine(DayOfWeek.Sunday.IsWeekend());
Console.WriteLine(DayOfWeek.Monday.IsWeekend());
}
}Mantenga i metodi puri quando possibile
I metodi di estensione che restituiscono un nuovo valore ed evitano gli effetti collaterali sono più facili da comprendere e concatenare. Punti a un flusso con input in entrata e valore in uscita.
using System;
public static class StringExtensions
{
// Pure: depends only on input, returns a new string
public static string Truncate(this string s, int max)
=> s.Length <= max ? s : s.Substring(0, max) + "...";
}
public class Program
{
public static void Main()
{
Console.WriteLine("Extension methods are great".Truncate(10));
}
}Gestisca gli input null
Poiché è possibile invocare un metodo di estensione su un ricevitore null, decida consapevolmente quale comportamento adottare. Gestisca null in modo appropriato oppure generi una ArgumentNullException chiara.
using System;
public static class StringExtensions
{
public static string SafeUpper(this string s)
{
if (s is null) throw new ArgumentNullException(nameof(s));
return s.ToUpper();
}
}
public class Program
{
public static void Main()
{
try { ((string)null).SafeUpper(); }
catch (ArgumentNullException ex) { Console.WriteLine("Caught: " + ex.ParamName); }
Console.WriteLine("ok".SafeUpper());
}
}Scelga nomi facili da individuare
Gli sviluppatori trovano i metodi di estensione digitando il punto e consultando IntelliSense. Nomi chiari, basati su verbi e descrittivi del risultato, rendono gli helper facili da individuare e autoesplicativi.
using System;
using System.Collections.Generic;
public static class CollectionExtensions
{
public static bool HasItems<T>(this ICollection<T> c)
=> c != null && c.Count > 0;
}
public class Program
{
public static void Main()
{
var list = new List<int> { 1 };
Console.WriteLine(list.HasItems());
}
}Raggruppi in modo coerente le estensioni correlate
Riunisca le estensioni relative a uno stesso concetto in una singola classe statica e in uno spazio dei nomi ben denominati. In questo modo le importazioni restano significative e gli utenti possono includere esattamente gli helper desiderati.
using System;
using System.Collections.Generic;
public static class EnumerableExtensions
{
public static IEnumerable<T> TakeFirst<T>(this IEnumerable<T> source, int n)
{
int taken = 0;
foreach (var item in source)
{
if (taken++ >= n) yield break;
yield return item;
}
}
}
public class Program
{
public static void Main()
{
var nums = new List<int> { 1, 2, 3, 4 };
Console.WriteLine(string.Join(",", nums.TakeFirst(2)));
}
}Non nasconda comportamenti sorprendenti
Un metodo di estensione che sembra poco costoso ma svolge un lavoro oneroso o dipende dallo stato viola le aspettative. Renda evidente il costo; se interroga un database o modifica lo stato, lo indichi adeguatamente nel nome.
using System;
public static class MathExtensions
{
// Cheap and obvious: no hidden cost
public static int ClampMin(this int value, int min)
=> value < min ? min : value;
}
public class Program
{
public static void Main()
{
Console.WriteLine((-3).ClampMin(0));
Console.WriteLine(5.ClampMin(0));
}
}Eviti di estendere object
Estendere object inquina ogni tipo del programma con il proprio metodo, ingombrando IntelliSense ovunque. Scelga invece il tipo o l'interfaccia più specifici che abbiano senso.
using System;
public static class IntExtensions
{
// Specific to int, not object - far less noisy
public static string ToOrdinal(this int n)
{
if (n % 10 == 1 && n % 100 != 11) return n + "st";
if (n % 10 == 2 && n % 100 != 12) return n + "nd";
if (n % 10 == 3 && n % 100 != 13) return n + "rd";
return n + "th";
}
}
public class Program
{
public static void Main()
{
Console.WriteLine(1.ToOrdinal());
Console.WriteLine(22.ToOrdinal());
}
}Preferisca restituire IEnumerable per le sequenze
Per gli operatori di sequenza, restituisca IEnumerable<T> e usi l'esecuzione differita. Questo favorisce la composizione ed evita di obbligare i chiamanti a materializzare dati di cui potrebbero non avere bisogno.
using System;
using System.Collections.Generic;
public static class SeqExtensions
{
public static IEnumerable<int> Doubled(this IEnumerable<int> source)
{
foreach (var n in source) yield return n * 2;
}
}
public class Program
{
public static void Main()
{
var nums = new List<int> { 1, 2, 3 };
foreach (var n in nums.Doubled()) Console.WriteLine(n);
}
}Una checklist per buoni metodi di estensione
Prima di distribuire un metodo di estensione, si chieda: il nome è chiaro? È puro oppure gli effetti collaterali sono evidenti? La gestione di null è corretta? Il tipo di destinazione è specifico? È raggruppato in modo sensato? Se la risposta è sì a tutte le domande, ha creato un helper che sarà piacevole da usare.
using System;
public static class StringExtensions
{
public static string OrDefault(this string s, string fallback)
=> string.IsNullOrEmpty(s) ? fallback : s;
}
public class Program
{
public static void Main()
{
Console.WriteLine("".OrDefault("N/A"));
Console.WriteLine("value".OrDefault("N/A"));
}
}Provi personalmente
Applichi la checklist: un tipo di destinazione specifico, un nome chiaro, la tolleranza a null e un risultato puro. Questa piccola estensione rispetta tutte le linee guida.
using System;
using System.Collections.Generic;
public static class DictionaryExtensions
{
// Clear name, specific type, null-safe, pure
public static TValue GetOrDefault<TKey, TValue>(
this IReadOnlyDictionary<TKey, TValue> dict, TKey key, TValue fallback)
{
if (dict == null) return fallback;
return dict.TryGetValue(key, out var value) ? value : fallback;
}
}
public class Program
{
public static void Main()
{
var ages = new Dictionary<string, int> { ["Ann"] = 30 };
Console.WriteLine(ages.GetOrDefault("Ann", -1));
Console.WriteLine(ages.GetOrDefault("Bob", -1));
}
}Verifica rapida
Applichi le linee guida di progettazione.
Riepilogo
Le estensioni ben progettate sembrano native e prevedibili.
- Preferisca helper puri che restituiscono valori e si concatenano facilmente.
- Decida e documenti il comportamento in presenza di
null. - Usi nomi chiari, basati su verbi, per facilitarne l'individuazione.
- Scelga tipi o interfacce specifici, non
object. - Raggruppi gli helper correlati e restituisca
IEnumerable<T>per le sequenze.
Domande Frequenti
La lezione «Progettazione di buone estensioni» è gratuita?
Sì — il testo completo di «Progettazione di buone estensioni» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 4 lezioni in totale.
Cosa imparerò in «Progettazione di buone estensioni»?
Applichi le best practice ed eviti le insidie. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare C# Academy?
Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Progettazione di buone estensioni»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione C# Academy?
Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Definizione dei metodi di estensione
- Estensione di interfacce e generics
- Risoluzione dei metodi di estensione
- Progettazione di buone estensioni