0Pricing
C# Academy · Lezione

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

  1. Definizione dei metodi di estensione
  2. Estensione di interfacce e generics
  3. Risoluzione dei metodi di estensione
  4. Progettazione di buone estensioni
← Torna a C# Academy