0Pricing
C# Academy · Lección

Resolución de métodos de extensión

Comprenda cómo encuentra el compilador las extensiones.

Resolución de métodos de extensión es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 4 lecciones en total.

Cómo encuentra el compilador las extensiones

Cuando escribe value.Method() y no hay ningún método de instancia coincidente, el compilador busca un método de extensión. Sin embargo, solo considera las extensiones cuyo espacio de nombres está en ámbito mediante una directiva using.

Las directivas using ponen las extensiones en ámbito

Una extensión solo está visible si importa su espacio de nombres. Sin el using adecuado, el método parece no existir, aunque esté compilado en el ensamblado.

using System;
using MyHelpers; // brings StringExtensions into scope

namespace MyHelpers
{
    public static class StringExtensions
    {
        public static string Reverse(this string s)
        {
            var arr = s.ToCharArray();
            Array.Reverse(arr);
            return new string(arr);
        }
    }
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine("hello".Reverse());
    }
}

Los métodos de instancia se comprueban primero

El compilador resuelve la llamada por etapas: primero busca un método de instancia coincidente, incluidos los heredados. Solo si ninguno encaja busca métodos de extensión.

using System;
using System.Collections.Generic;

public static class ListExt
{
    // Ignored: List<int> already has Add(int)
    public static void Add(this List<int> list, int a, int b)
        => list.Add(a + b);
}

public class Program
{
    public static void Main()
    {
        var list = new List<int>();
        list.Add(5); // the built-in instance Add wins for this signature
        Console.WriteLine(list[0]);
    }
}

Se prefieren los espacios de nombres más cercanos

Si coinciden dos extensiones, gana la que pertenece al espacio de nombres más cercano en la jerarquía de anidamiento. Una ambigüedad que el compilador no puede resolver provoca un error de compilación y le obliga a desambiguar.

using System;

namespace Outer
{
    public static class A { public static string Tag(this int n) => "A" + n; }

    namespace Inner
    {
        public static class B { public static string Tag(this int n) => "B" + n; }

        public class Program
        {
            public static void Main()
            {
                // B is in the nearer (Inner) namespace, so it is preferred
                Console.WriteLine(7.Tag());
            }
        }
    }
}

Desambiguar mediante una llamada estática

Cuando las extensiones entran en conflicto o quiere ser explícito, llame directamente al método estático mediante el nombre completo de su clase. De este modo, evita por completo la resolución de extensiones.

using System;

public static class FormatExt
{
    public static string Bracket(this string s) => "[" + s + "]";
}

public class Program
{
    public static void Main()
    {
        // Explicit static call, no ambiguity possible
        Console.WriteLine(FormatExt.Bracket("x"));
    }
}

Resolución de sobrecargas entre extensiones

Si varios métodos de extensión comparten un nombre, la resolución normal de sobrecargas elige la mejor coincidencia según los tipos de los parámetros, igual que en una sobrecarga de métodos ordinaria.

using System;

public static class PrintExt
{
    public static string Describe(this int n) => "int:" + n;
    public static string Describe(this string s) => "str:" + s;
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(42.Describe());
        Console.WriteLine("hi".Describe());
    }
}

Inferencia genérica durante la resolución

En las extensiones genéricas, el compilador infiere los argumentos de tipo a partir del receptor y de los argumentos. Si la inferencia falla, la extensión no se tiene en cuenta.

using System;
using System.Collections.Generic;

public static class SeqExt
{
    public static T FirstItem<T>(this IEnumerable<T> source)
    {
        foreach (var item in source) return item;
        throw new InvalidOperationException("empty");
    }
}

public class Program
{
    public static void Main()
    {
        var nums = new List<int> { 5, 6, 7 };
        // T inferred as int from the List<int> receiver
        Console.WriteLine(nums.FirstItem());
    }
}

global using e importaciones implícitas

El C# moderno permite declarar directivas global using para que un espacio de nombres esté en ámbito en todo el proyecto. Así, las bibliotecas de extensiones compartidas están disponibles en todas partes sin repetir las importaciones.

using System;

// In a real project a separate file might say: global using MyHelpers;
namespace MyHelpers
{
    public static class IntExt { public static int Twice(this int n) => n * 2; }
}

public class Program
{
    public static void Main()
    {
        // Works here because MyHelpers is referenced explicitly
        Console.WriteLine(MyHelpers.IntExt.Twice(8));
    }
}

Cuando importa el tipo receptor

La resolución depende del tipo estático del receptor, no de su tipo en tiempo de ejecución. Una extensión declarada para un tipo base se aplica incluso cuando la variable contiene una instancia derivada, salvo que haya una extensión más específica en ámbito.

using System;

public class Animal { }
public class Cat : Animal { }

public static class AnimalExt
{
    public static string Kind(this Animal a) => "animal";
}

public class Program
{
    public static void Main()
    {
        Animal a = new Cat();
        // Chosen by static type Animal
        Console.WriteLine(a.Kind());
    }
}

Un modelo mental para la resolución

Considere el orden de esta forma: (1) métodos de instancia; después, (2) métodos de extensión de los espacios de nombres importados, empezando por los más cercanos; y, por último, (3) resolución de sobrecargas entre los candidatos. Conocer este orden explica casi todos los resultados inesperados.

using System;

public static class Ext
{
    public static string Wrap(this string s) => "<" + s + ">";
}

public class Program
{
    public static void Main()
    {
        // No instance Wrap exists, so the extension is used
        Console.WriteLine("node".Wrap());
    }
}

Pruébelo usted mismo

Defina una extensión en un espacio de nombres, impórtela y llámela. Después, llame explícitamente al mismo método como método estático para comprobar que ambas formas funcionan.

using System;
using Text.Helpers;

namespace Text.Helpers
{
    public static class StringExtensions
    {
        public static int Vowels(this string s)
        {
            int count = 0;
            foreach (var c in s.ToLower())
                if ("aeiou".IndexOf(c) >= 0) count++;
            return count;
        }
    }
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine("education".Vowels());
        Console.WriteLine(Text.Helpers.StringExtensions.Vowels("education"));
    }
}

Comprobación rápida

Considere qué hace que un método de extensión sea visible.

Recapitulación

La resolución de métodos de extensión sigue un orden claro.

  • Primero se prueban los métodos de instancia; las extensiones solo cubren lo que falta.
  • Una extensión solo está visible si su espacio de nombres está en ámbito mediante using o global using.
  • Ganan los espacios de nombres más cercanos; los empates que no se pueden resolver producen errores de compilación.
  • Siempre puede llamar explícitamente al método estático para desambiguar.
  • La resolución usa el tipo estático del receptor.

Preguntas frecuentes

¿La lección «Resolución de métodos de extensión» es gratis?

Sí — el texto completo de «Resolución de métodos de extensión» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Resolución de métodos de extensión»?

Comprenda cómo encuentra el compilador las extensiones. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C# Academy?

No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Resolución de métodos de extensión»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C# Academy?

Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Definición de métodos de extensión
  2. Extensión de interfaces y genéricos
  3. Resolución de métodos de extensión
  4. Diseño de buenas extensiones
← Volver a C# Academy