2011-02-04 17 views
56

estoy usando LINQ to XMLComo hacer funciones en línea en C#

new XElement("Prefix", Prefix == null ? "" : Prefix) 

pero quiero hacer algún cálculo para el prefijo antes de añadir a la xml, como espacios eliminando, caracteres especiales, algunos cálculos etc

No quiero crear funciones porque estas no serán de ninguna ayuda en ninguna otra parte de mi programa, pero esto, ¿hay alguna manera de crear funciones en línea?

+1

No se prohíba crear una función simplemente porque no se llamará desde ningún otro lugar. Las funciones también se pueden usar para limpiar el código (si tiene un procedimiento grande que abarca varias páginas, dividirlo en funciones lo hace más legible) y autoeditarlo (simplemente nombrar una función correctamente puede transmitir información al lector). – Joe

+0

Si vino aquí desde Google y desea saber cómo emular las funciones en línea en C#, vaya aquí: https://stackoverflow.com/questions/473782/inline-functions-in-c Las respuestas a continuación no se refieren a funciones "en línea" en el verdadero sentido de la palabra, y C# ni siquiera tiene funciones en línea verdaderas, pero el enlace anterior proporciona una optimización del compilador que se puede usar. – James

Respuesta

131

Sí, C# lo admite. Hay varias sintaxis disponibles:

  • Anonymous methods (disponible de C# 2 en adelante)

    Func<int, int, int> add = delegate(int x, int y) 
            { 
             return x + y; 
            }; 
    Action<int> print = delegate(int x) 
            { 
             Console.WriteLine(x); 
            } 
    Action<int> helloWorld = delegate // parameters can be elided if ignored 
             { 
              Console.WriteLine("Hello world!"); 
             } 
    
  • Expresión Lambdas (disponible de C# 3 en adelante)

    Func<int, int, int> add = (int x, int y) => x + y; // or... 
    Func<int, int, int> add = (x,y) => x + y; // types are inferred by the compiler 
    
  • lambdas declaración (disponible desde C# 3 en adelante)

    Action<int> print = (int x) => { Console.WriteLine(x); }; 
    Action<int> print = x => { Console.WriteLine(x); }; // inferred types 
    Func<int, int, int> add = (x,y) => { return x + y; }; 
    

Hay básicamente dos tipos diferentes de éstos: Func y Action. Func s valores de retorno pero Action s no. El último parámetro de tipo de Func es el tipo de retorno; todos los demás son los tipos de parámetros.

Existen tipos similares con nombres diferentes, pero la sintaxis para declararlos en línea es la misma. Un ejemplo de esto es Comparison<T>, que es aproximadamente equivalente a Func<T,T,int>.

Func<string,string,int> compare1 = (l,r) => 1; 
Comparison<string> compare2 = (l,r) => 1; 
Comparison<string> compare3 = compare1; // this one only works from C# 4 onwards 

Estos se pueden invocar directamente como si fueran métodos habituales:

int x = add(23,17); // x == 40 
print(x); // outputs 40 
helloWorld(x); // helloWord has one int parameter declared: Action<int> 
       // even though it does not make any use of it. 
+1

Respuesta muy bien elaborada: D –

+1

No entiendo esta respuesta.En su ejemplo, quiere que XElement nuevo ("Prefix", prefix => newPrefix) se declare en línea. Todas estas respuestas equivalen a declarar una nueva función. ¿Por qué no declarar una nueva función? –

+0

porque: 1. para comprender la lógica del método de lectura de la función en línea es mucho más fácil que buscar diferentes declaraciones 2. con frecuencia necesita escribir menos código al usar las funciones en línea – Vova

15

Sí.

Puede crear anonymous methods o lambda expressions:

Func<string, string> PrefixTrimmer = delegate(string x) { 
    return x ?? ""; 
}; 
Func<string, string> PrefixTrimmer = x => x ?? ""; 
+0

Gracias por su respuesta, ¿podría elaborar un poco más sobre la respuesta, la lamba uno, quiero decir el 'código'Func PrefixTrimmer = x => x ?? ""; 'código' soy nuevo en esto y realmente no entiendo muy bien el documento de MSDN –

+2

@Joe:' x ?? "" 'es el operador de fusión nula. http://msdn.microsoft.com/en-us/library/ms173224.aspx – SLaks

+0

En 'x => (algo)', 'x' es un parámetro, y' (algo) 'es el valor de retorno'. – SLaks

5

Puede utilizar Func que encapsula un método que tiene un parámetro y devuelve un valor del tipo especificado por el parámetro TResult.

void Method() 
{ 
    Func<string,string> inlineFunction = source => 
    { 
     // add your functionality here 
     return source ; 
    }; 


    // call the inline function 
    inlineFunction("prefix"); 
} 
9

La respuesta a su pregunta es sí y no, dependiendo de lo que entendemos por "función en línea". Si está utilizando el término como se usa en el desarrollo de C++, entonces la respuesta es no, no puede hacer eso, incluso una expresión lambda es una llamada a función. Si bien es cierto que puede definir expresiones lambda en línea para reemplazar declaraciones de funciones en C#, el compilador aún termina creando una función anónima.

Aquí hay un código muy simple que utiliza para probar esto (VS2015):

static void Main(string[] args) 
    { 
     Func<int, int> incr = a => a + 1; 
     Console.WriteLine($"P1 = {incr(5)}"); 
    } 

Lo que genera el compilador? Utilicé una herramienta ingeniosa llamada ILSpy que muestra el ensamblaje de IL real generado.Echar un vistazo (he omitido muchas cosas configuración de clase)

Ésta es la función principal:

 IL_001f: stloc.0 
     IL_0020: ldstr "P1 = {0}" 
     IL_0025: ldloc.0 
     IL_0026: ldc.i4.5 
     IL_0027: callvirt instance !1 class [mscorlib]System.Func`2<int32, int32>::Invoke(!0) 
     IL_002c: box [mscorlib]System.Int32 
     IL_0031: call string [mscorlib]System.String::Format(string, object) 
     IL_0036: call void [mscorlib]System.Console::WriteLine(string) 
     IL_003b: ret 

ver esas líneas IL_0026 y IL_0027? Esas dos instrucciones cargan el número 5 y llaman a una función. Luego, formatee IL_0031 e IL_0036 e imprima el resultado.

Y aquí es la función llamada:

 .method assembly hidebysig 
      instance int32 '<Main>b__0_0' (
       int32 a 
      ) cil managed 
     { 
      // Method begins at RVA 0x20ac 
      // Code size 4 (0x4) 
      .maxstack 8 

      IL_0000: ldarg.1 
      IL_0001: ldc.i4.1 
      IL_0002: add 
      IL_0003: ret 
     } // end of method '<>c'::'<Main>b__0_0' 

Es una función muy corto, pero es una función.

¿Vale la pena hacer un esfuerzo para optimizar? Nah. Tal vez si lo está llamando miles de veces por segundo, pero si el rendimiento es tan importante, entonces debería considerar llamar al código nativo escrito en C/C++ para hacer el trabajo.

En mi experiencia, la capacidad de lectura y la facilidad de mantenimiento son casi siempre más importantes que la optimización de unos pocos microsegundos para ganar velocidad. Use funciones para hacer que su código sea legible y para controlar el alcance de las variables y no se preocupe por el rendimiento.

"La optimización prematura es la raíz de todos los males (o al menos la mayoría) en la programación." - Donald Knuth

"Un programa que no se ejecuta correctamente no tiene que correr rápido" - Me

+0

muy útil, gracias – aaron

5

C# 7 añade soporte para local functions

Aquí está el ejemplo anterior utilizando una función local

void Method() 
{ 
    string localFunction(string source) 
    { 
     // add your functionality here 
     return source ; 
    }; 

    // call the inline function 
    localFunction("prefix"); 
} 
0

No solo en los métodos internos, también se puede utilizar dentro de las clases.

class Calculator 
    { 
     public static int Sum(int x,int y) => x + y; 
     public static Func<int, int, int> Add = (x, y) => x + y; 
     public static Action<int,int> DisplaySum = (x, y) => Console.WriteLine(x + y); 
    }