Implementación de métodos de extensión para una clase
Normalmente, hay dos maneras de agregar un método a un tipo existente:
- Modifique el código fuente de ese tipo. Al modificar el origen se crea un cambio importante si también se agregan campos de datos privados para admitir el método .
- Defina el nuevo método en una clase derivada. No se puede agregar un método de esta manera mediante la herencia para otros tipos, como estructuras y enumeraciones. Tampoco se puede usar para "agregar" un método a una clase sellada.
Los métodos de extensión permiten "agregar" un método a un tipo existente sin modificar el propio tipo ni implementar el nuevo método en un tipo heredado. El método de extensión tampoco tiene que residir en el mismo ensamblado que el tipo que extiende. Se llama a un método de extensión como si fuera un miembro definido de un tipo.
Métodos de extensión
Los métodos de extensión permiten "agregar" métodos a tipos existentes sin crear un nuevo tipo derivado, volver a compilar o modificar el tipo original. Los métodos de extensión son métodos estáticos, pero se les llama como si fueran métodos de instancia en el tipo extendido. Para el código de cliente escrito en C#, F# y Visual Basic, no hay ninguna diferencia aparente entre llamar a un método de extensión y los métodos definidos en un tipo.
Enlazar métodos de extensión en tiempo de compilación
Puede usar métodos de extensión para extender una clase o interfaz, pero no para invalidarlos. Nunca se llama a un método de extensión con el mismo nombre y firma que un método de clase. En tiempo de compilación, los métodos de extensión siempre tienen una prioridad menor que los métodos de instancia definidos en el propio tipo. En otras palabras, si un tipo tiene un método denominado Process(int i)y tiene un método de extensión con la misma firma, el compilador siempre se enlaza al método de instancia. Cuando el compilador encuentra una invocación de método, busca una coincidencia en los métodos de instancia del tipo. Si no se encuentra ningún método de instancia coincidente, el compilador busca los métodos de extensión definidos para el tipo. El compilador se enlaza al primer método de extensión que encuentra.
En el ejemplo siguiente se muestran las reglas que sigue el compilador de C# para determinar si se debe enlazar una llamada de método a un método de instancia en el tipo o a un método de extensión.
namespace ExtensionMethodDemo.PersonNamespace
{
// Define a simple class with properties and methods
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public void Introduce()
{
Console.WriteLine($"Hi, I'm {FirstName} {LastName}, and I'm {Age} years old.");
}
}
}
namespace ExtensionMethodDemo.PersonExtensionsNamespace
{
using ExtensionMethodDemo.PersonNamespace;
// Define an extension method for the Person class
public static class PersonExtensions
{
public static void DisplayFullName(this Person person)
{
Console.WriteLine($"Full Name: {person.FirstName} {person.LastName}");
}
public static bool IsAdult(this Person person)
{
return person.Age >= 18;
}
public static void Introduce()
{
Console.WriteLine($"Extension - Hi, it's nice to meet you.");
}
// Extension method attempting to override Introduce
public static void Introduce(this Person person, string greeting)
{
Console.WriteLine($"{greeting}, I'm {person.FirstName} {person.LastName}, and I'm {person.Age} years old.");
}
}
}
namespace ExtensionMethodDemo
{
using ExtensionMethodDemo.PersonNamespace;
using ExtensionMethodDemo.PersonExtensionsNamespace;
class Program
{
static void Main(string[] args)
{
// Create instances of the Person class
Person person1 = new Person { FirstName = "FName1", LastName = "LName1", Age = 25 };
Person person2 = new Person { FirstName = "FName2", LastName = "LName2", Age = 16 };
// Use the methods of the Person class
person1.Introduce();
person2.Introduce();
// Use the extension methods
person1.DisplayFullName();
Console.WriteLine($"Is {person1.FirstName} an adult? {person1.IsAdult()}");
person2.DisplayFullName();
Console.WriteLine($"Is {person2.FirstName} an adult? {person2.IsAdult()}");
// Use the extension method that attempts to override Introduce
person1.Introduce("Hello");
person2.Introduce("Greetings");
}
}
}
// Output:
// Hi, I'm FName1 LName1, and I'm 25 years old.
// Hi, I'm FName2 LName2, and I'm 16 years old.
// Full Name: FName1 LName1
// Is FName1 an adult? True
// Full Name: FName2 LName2
// Is FName2 an adult? False
// Hello, I'm FName1 LName1, and I'm 25 years old.
// Greetings, I'm FName2 LName2, and I'm 16 years old.
En este ejemplo, la clase Person tiene tres propiedades: FirstName, LastNamey Age. La clase Person también tiene un método de instancia Introduce que escribe un mensaje en la consola.
La clase PersonExtensions define métodos de extensión para la clase Person. La clase PersonExtensions contiene los siguientes métodos de extensión:
-
DisplayFullName: escribe el nombre completo de la persona en la consola. -
IsAdult: devuelve un valor booleano que indica si la persona es un adulto. -
Introduce: escribe un mensaje en la consola. Este método tiene dos sobrecargas: una sin parámetros y otra con un parámetro de cadena. -
Introduce(this Person person, string greeting): escribe un mensaje en la consola con un saludo personalizado. -
Introduce(): escribe un mensaje predeterminado en la consola.
El método Main crea dos instancias de la clase Person y llama al método Introduce en cada instancia. Se ejecuta el método Introduce definido en la clase Person. No se llama al método Introduce sin parámetros de la clase PersonExtensions porque la clase Person ya tiene un método de instancia Introduce con la misma firma. El compilador sigue las reglas para enlazar métodos de extensión en tiempo de compilación y da prioridad al método de instancia definido en el propio tipo. El método Main también llama a los métodos de extensión DisplayFullName, IsAdulty al método Introduce sobrecargado con un saludo personalizado. Los métodos de extensión se ejecutan según lo previsto.
Directrices generales
Los métodos de extensión son una opción importante para crear funcionalidad reutilizable en todo el ecosistema de .NET. Sin embargo, la modificación del código de un objeto o la derivación de un nuevo tipo siempre que sea razonable y posible hacerlo, se considera preferible. Los métodos de extensión son una excelente opción cuando el origen original no está bajo su control, cuando un objeto derivado es inadecuado o imposible, o cuando la funcionalidad no debe exponerse más allá de su ámbito aplicable.
Cuando se usan métodos de extensión para extender un tipo cuyo código fuente no está en control de , corre el riesgo de que un cambio en la implementación del tipo hará que el método de extensión se interrumpa. Si implementa métodos de extensión para un tipo determinado, recuerde los siguientes puntos:
- No se llama a un método de extensión si tiene la misma firma que un método definido en el tipo .
- Los métodos de extensión se incluyen en el ámbito en el nivel de espacio de nombres. Por ejemplo, si tiene varias clases estáticas que contienen métodos de extensión en un único espacio de nombres denominado
Extensions, todos se incluirán en el ámbito mediante la directivausing Extensions;.
Para una biblioteca de clases que implementó, no debe usar métodos de extensión para evitar incrementar el número de versión de un ensamblado. Si desea agregar una funcionalidad significativa a una biblioteca para la que posee el código fuente, siga las instrucciones de .NET para el control de versiones de ensamblado.