Kata: Array Helpers - 6 kyu
Situation: This kata is designed to test your ability to extend the functionality of built-in classes. In this case, we want you to extend the built-in Array
class with the following methods: Square()
, Cube()
, Average()
, Sum()
, Even()
and Odd()
.
Explanation:
Square()
must return a copy of the array, containing all values squaredCube()
must return a copy of the array, containing all values cubedAverage()
must return the average of all array values; on an empty array must returnNaN
Sum()
must return the sum of all array valuesEven()
must return an array of all even numbersOdd()
must return an array of all odd numbers
Note: the original array must not be changed in any case!
Situación: Este kata está diseñado para probar tu habilidad para extender la funcionalidad de las clases incorporadas. En este caso, queremos que extiendas la clase incorporada
Array
con los siguientes métodos:Square()
,Cube()
,Average()
,Sum()
,Even()
yOdd()
.Explicación:
Square()
debe devolver una copia de la matriz, que contiene todos los valores al cuadradoCube()
debe devolver una copia de la matriz, que contiene todos los valores al cuboAverage()
debe devolver la media de todos los valores de la matriz; en una matriz vacía debe devolverNaN
Sum()
debe devolver la suma de todos los valores de la matrizEven()
debe devolver una matriz con todos los números paresOdd()
debe devolver una matriz con todos los números imparesNota: la matriz original no debe ser cambiada bajo ninguna circunstancia!
Example:
The exercise itself has no difficulty. Its rating of 6 kyu
, in my opinion, refers to the knowledge of the concept it addresses: “extending class functionalities” and is therefore worthwhile to explain the use of the this
keyword and extension methods.
El ejercicio en sí no tiene ninguna dificultad. Su calificación de
6 kyu
, en mi opinión, se refiere al conocimiento del concepto que aborda: “extender funcionalidades de clases” y, por tanto, vale la pena para explicar el uso de la palabra reservadathis
y los métodos de extensión.
Extension methods [Métodos de extensión]
Extension methods enable you to "add" methods to existing types (class
, struct
or interface
) without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are static methods, but they're called as if they were instance methods on the extended type. For client code written in C#
there's no apparent difference between calling an extension method and the methods defined in a type. They are declared by placing the this
keyword in front of the first parameter of the method. The data type of the parameter indicates which type is going to be extended. Note that this parameter is not included in the call (if the call is made from the extended type). The method must be declared in a non-nested and non-generic class, although the method itself can be perfectly generic. Extension methods are only in scope when you explicitly import the namespace into your source code with a using
directive.
Los métodos de extensión permiten “agregar” métodos a los tipos existentes (
class
,struct
ointerface
) sin tener que crear un nuevo tipo que herede del actual, volver a compilar o modificar el tipo original. Los métodos de extensión se definen como métodos estáticos, pero se llaman mediante la sintaxis del método de instancia. En el caso del código de cliente escrito enC#
, no hay ninguna diferencia aparente entre llamar a un método de extensión y los métodos definidos en un tipo. Se declaran colocando la palabra reservadathis
delante del primer parámetro del método. El tipo de dato del parámetro indica cual es el tipo que va a ser extendido. Ten en cuenta que este parámetro no se incluye en la llamada (si la llamada se hace desde el tipo extendido). El método debe ser declarado en una clase no anidada y no genérica, aunque el método en sí puede ser perfectamente genérico. Los métodos de extensión sólo están en el ámbito de aplicación cuando se importa explícitamente el espacio de nombres en el código fuente con una directivausing
.
The intermediate language (IL) generated by the compiler translates your code into a call on the static method. The principle of encapsulation isn't really being violated, since extension methods can't access private variables in the type they're extending.
El lenguaje intermedio (IL) generado por el compilador traduce el código en una llamada al método estático. En ningún momento se viola el principio de encapsulación, pues los métodos de extensión no pueden acceder a variables privadas del tipo que están extendiendo.
Both the MyExtensions
class and the WordCount()
method are static
, and it can be accessed like all other static
members. The WordCount()
method can be invoked like other static
methods as follows:
Tanto la clase
MyExtensions
como el métodoWordCount()
son estáticos, y se puede acceder a ellos como a todos los demás miembros estáticos. El métodoWordCount()
puede ser invocado como otros métodos estáticos de la siguiente manera:
You can use extension methods to extend a class or interface, but not to override them. An extension method with the same name and signature as an interface or class method will never be called. At compile time, extension methods always have lower priority than instance methods defined in the type itself. In other words, if a type has a method named Process(int i)
, and you have an extension method with the same signature, the compiler will always bind to the instance method. When the compiler encounters a method invocation, it first looks for a match in the type's instance methods. If no match is found, it searches for any extension methods that are defined for the type, and bind to the first extension method that it finds.
The following code demonstrates what was expressed in the previous paragraph. The static class Extension
contains extension methods defined for any type that implements IMyInterface
. Classes A
, B
, and C
all implement the interface. The MethodB
extension method is never called because its name and signature exactly match methods already implemented by the classes. When the compiler can't find an instance method with a matching signature, it will bind to a matching extension method if one exists.
Los métodos de extensión se pueden usar para extender una clase o interfaz, pero no para sobrescribirlas. Un método de extensión con el mismo nombre y firma que un método de clase o interfaz nunca será invocado. En tiempo de compilación los métodos de extensión siempre tienen menor prioridad que los métodos de instancia que ya estaban definidos en el propio tipo. En otras palabras, si un tipo tiene un método llamado
Process(int i)
, y tienes un método de extensión con la misma firma, el compilador siempre dará prioridad al método de instancia. Cuando el compilador encuentra una invocación a un método, primero busca una coincidencia en los métodos de instancia del tipo. Si no encuentra ninguna coincidencia, busca cualquier método de extensión que esté definido, y se enlaza al primer método de extensión que encuentre con la misma firma.
El siguiente código demuestra lo expresado en el párrafo anterior. La clase estáticaExtension
contiene métodos de extensión definidos para cualquier tipo que implementeIMyInterface
. Las clasesA
,B
yC
implementan la interfaz. El método de extensiónMethodB()
nunca se llama porque su nombre y firma coinciden exactamente con los métodos ya implementados por las clases. Cuando el compilador no puede encontrar un método de instancia con una firma coincidente, se enlazará a un método de extensión coincidente si existe uno.
Extending predefined types can be difficult with struct
types because they're passed by value to methods. That means any changes to the struct
are made to a copy of the struct
. Those changes aren't visible once the extension method exits. You can add the ref
modifier to the first argument making it a ref
extension method. The ref
keyword can appear before or after the this
keyword without any semantic differences.
Since adding the ref
modifier indicates that the first argument is passed by reference, this enables you to write extension methods that change the state of the struct
being extended. Only value types or generic types constrained to struct are allowed as the first parameter of a ref
extension method. The following example shows how to use a ref
extension method to directly modify a built-in type without the need to reassign the result or pass it through a function with the ref
keyword:
Extender tipos predefinidos puede ser difícil cuando se trata con
struct
, ya que se pasan por valor a los métodos. Esto significa que cualquier cambio en elstruct
se realiza en una copia delstruct
. Esos cambios no son visibles una vez que la ejecución del método termina. Puedes añadir el modificadorref
al primer argumento, convirtiéndolo en un método de extensión que funciona por referencia. La palabra claveref
puede aparecer antes o después de la palabra clavethis
sin que exista ninguna diferencia semántica.Ya que añadir el modificador
ref
indica que el primer argumento se pasa por referencia, esto permite escribir métodos de extensión que cambian el estado delstruct
que se está extendiendo. Sólo se permiten como primer parámetro de un método de extensiónref
los tipos de valor o los tipos genéricos. El siguiente ejemplo muestra cómo utilizar un método de extensiónref
para modificar directamente un tipo incorporado sin necesidad de reasignar el resultado o pasarlo a través de una función con la palabra claveref
:
While it's still considered preferable to add functionality by modifying an object's code or deriving a new type whenever it's reasonable and possible to do so, extension methods have become a crucial option for creating reusable functionality in C#
and throughout the .NET
ecosystem. When using an extension method to extend a type whose source code you aren't in control of, you run the risk that a change in the implementation of the type will cause your extension method to break. For those occasions when the original source isn't under your control, when a derived object is inappropriate or impossible, or when the functionality shouldn't be exposed beyond its applicable scope, extension methods are an excellent choice. For example, if we try to inherit from the Array
class, the following error message will be thrown: Extensions
cannot be derived from the special Array
class (CS0644). If we click on the link it will take us to Microsoft Learn, the official C# and .NET documentation, and we will see the compilation error CS0644
: Classes cannot explicitly inherit from any of the following base classes:
System.Enum
System.ValueType
System.Delegate
System.Array
The compiler uses them as implicit base classes. For example, System.ValueType
is the implicit base class for struct
.
Aunque todavía se considera preferible añadir funcionalidad modificando el código de un objeto o creando un nuevo tipo que herede de otro ya existente, siempre que sea razonable y posible hacerlo, los métodos de extensión son una opción crucial para crear funcionalidad reutilizable en
C#
y todo el ecosistema.NET
en general. Cuando se utiliza un método de extensión para extender un tipo cuyo código fuente no controlas, se corre el riesgo de que un cambio en la implementación del tipo provoque la rotura del método de extensión. Para aquellas ocasiones en las que la fuente original no está bajo tu control directo, cuando la funcionalidad no debe exponerse más allá de su ámbito aplicable, o cuando es inapropiado o imposible derivar de otro tipo, los métodos de extensión son una excelente opción. Por ejemplo, si intentamos heredar de la claseArray
, se lanzará el siguiente mensaje de error:Extensions
no se puede derivar de la clase especialArray
(CS0644). Si pinchamos el enlace nos llevará a Microsoft Learn, la documentación oficial deC#
y.NET
, y veremos el error de compilaciónCS0644
: Las clases no pueden heredar explícitamente de ninguna de las siguientes clases base:
System.Enum
System.ValueType
System.Delegate
System.Array
El compilador las utiliza como clases base implícitas. Por ejemplo,
System.ValueType
es la clase base implícita de losstruct
.
So it's all for today's blog. In the next one I will be giving a solution to the exercise. Click here to go.
Esto es todo por ahora. En el próximo blog estaré dándole solución al ejercicio. Pincha aquí para ir.
Bibliography [Bibliografía]
Extension Methods - C# | Microsoft Learn
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods
Compile Error CS0644 | Microsoft Learn
https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0644?f1url=%3FappId%3Droslyn%26k%3Dk
C# in Depth 4th edition - Jon Skeet
English translation made with DeepL Translate
Traducción al Inglés hecha con Deepl Translate