visual que programacion polimorfico metodos metodo llamar funciones extension ejemplo declara como clases c# extension-methods encapsulation

c# - que - ¿Puede haber métodos de extensión privados?



metodos y funciones en c# (5)

¿Hay alguna razón convincente para este requisito?

Esa es la pregunta incorrecta para hacer. La pregunta formulada por el equipo de diseño de idiomas cuando estábamos diseñando esta característica fue:

¿Hay alguna razón convincente para permitir que los métodos de extensión se declaren en tipos estáticos anidados?

Dado que los métodos de extensión se diseñaron para hacer que LINQ funcione, y LINQ no tiene escenarios donde los métodos de extensión serían privados para un tipo, la respuesta fue "no, no hay una razón tan convincente".

Al eliminar la posibilidad de poner métodos de extensión en tipos anidados estáticos, ninguna de las reglas para buscar métodos de extensión en tipos anidados estáticos debía ser pensada, discutida, diseñada, especificada, implementada, probada, documentada, enviada a los clientes o hecho compatible con cada característica futura de C # . Eso fue un ahorro de costos significativo.

Digamos que necesito un método de ayuda privada simple, e intuitivamente en el código tendría sentido como método de extensión. ¿Hay alguna manera de encapsular ese ayudante a la única clase que realmente necesita usarlo?

Por ejemplo, trato de esto:

class Program { static void Main(string[] args) { var value = 0; value = value.GetNext(); // Compiler error } static int GetNext(this int i) { return i + 1; } }

El compilador no "ve" el método de extensión GetNext() . El error es:

El método de extensión debe definirse en una clase estática no genérica

Bastante, así que lo envuelvo en su propia clase, pero aún encapsulado dentro del objeto al que pertenece:

class Program { static void Main(string[] args) { var value = 0; value = value.GetNext(); // Compiler error } static class Extensions { static int GetNext(this int i) { return i + 1; } } }

Todavía no hay dados. Ahora el error dice:

El método de extensión se debe definir en una clase estática de nivel superior; Extensiones es una clase anidada.

¿Hay alguna razón convincente para este requisito? Hay casos en los que un método de ayuda realmente debe estar encapsulado de forma privada, y hay casos donde el código es mucho más limpio y más legible / compatible si un método de ayuda es un método de extensión. Para los casos en que estos dos se cruzan, ¿ambos se pueden satisfacer o tenemos que elegir uno sobre el otro?


Creo que es la forma en que implementaron la compilación de los Métodos de Extensiones.

Al observar el IL, parece que agregan algunos atributos adicionales al método.

.method public hidebysig static int32 GetNext(int32 i) cil managed { .custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() .maxstack 2 .locals init ( [0] int32 num) L_0000: nop L_0001: ldarg.0 L_0002: ldc.i4.1 L_0003: add L_0004: dup L_0005: starg.s i L_0007: stloc.0 L_0008: br.s L_000a L_000a: ldloc.0 L_000b: ret }

Probablemente hay algunos muy fundamentales que nos faltan que simplemente no lo hacen funcionar, y por eso la restricción está en su lugar. También podría ser que quisieran forzar las prácticas de codificación. Desafortunadamente, simplemente no funciona y tiene que estar en clases estáticas de nivel superior.


Creo que lo mejor que se puede obtener en un caso general es internal static clase internal static métodos internal static extensión internal static . Dado que estará en su propio ensamblado, las únicas personas que necesita para evitar el uso de la extensión son los autores del ensamblado, por lo que algunos espacios de nombres explícitamente nombrados (como My.Extensions.ForFoobarOnly ) pueden ser suficientes para evitar el uso indebido.

La restricción internal mínima cubierta en el artículo de extensión del apero

La clase debe ser visible para el código de cliente ... método con al menos la misma visibilidad que la clase contenedora.

Nota: Haría la extensión pública de todos modos para simplificar las pruebas unitarias, pero Xxxx.Yyyy.Internal espacio de nombres explícitamente nombrado como Xxxx.Yyyy.Internal para que otros usuarios del ensamblado no esperaran que los métodos fueran compatibles / invocables. Esencialmente se basan en la convención que no sea la compilación del tiempo de compilación.


Este código compila y funciona:

static class Program { static void Main(string[] args) { var value = 0; value = value.GetNext(); // Compiler error } static int GetNext(this int i) { return i + 1; } }

Preste atención a static class Program línea de static class Program que era lo que el compilador dijo que se necesitaba.


Esto se toma de un ejemplo en microsoft msdn. Los métodos Extesnion se deben definir en una clase estática. Vea cómo se definió la clase de Static en un espacio de nombre diferente e importado en. Puede ver un ejemplo aquí http://msdn.microsoft.com/en-us/library/bb311042(v=vs.90).aspx

namespace TestingEXtensions { using CustomExtensions; class Program { static void Main(string[] args) { var value = 0; Console.WriteLine(value.ToString()); //Test output value = value.GetNext(); Console.WriteLine(value.ToString()); // see that it incremented Console.ReadLine(); } } } namespace CustomExtensions { public static class IntExtensions { public static int GetNext(this int i) { return i + 1; } } }