Funciones en línea en C #?

¿Cómo se hacen las “funciones en línea” en C #? No creo entender el concepto. ¿Son como métodos anónimos? Al igual que las funciones lambda?

Nota : Las respuestas se refieren casi por completo a la capacidad de funciones en línea , es decir, “una optimización manual o de comstackción que reemplaza un sitio de llamada de función con el cuerpo del destinatario”. Si le interesan las funciones anónimas (aka lambda) , consulte la respuesta de @ jalf o ¿Qué es esta ‘Lambda’ de la que todo el mundo sigue hablando? .

Finalmente, en .NET 4.5, el CLR permite insinuar / sugerir 1 método en línea usando MethodImplOptions.AggressiveInlining value. También está disponible en el maletero del Mono (comprometido hoy).

 // The full attribute usage is in mscorlib.dll, // so should not need to include extra references using System.Runtime.CompilerServices; ... [MethodImpl(MethodImplOptions.AggressiveInlining)] void MyMethod(...) 

1 . Anteriormente se usaba “fuerza” aquí. Como hubo algunos votos negativos, trataré de aclarar el término. Como en los comentarios y la documentación, The method should be inlined if possible. Especialmente considerando Mono (que está abierto), hay algunas limitaciones técnicas monoespecíficas que se consideran en línea o más generales (como funciones virtuales). En general, sí, esto es una pista para el comstackdor, pero supongo que eso es lo que se pidió.

Los métodos en línea son simplemente una optimización del comstackdor en la que el código de una función se transfiere a la persona que llama.

No hay ningún mecanismo para hacerlo en C #, y deben usarse con moderación en los idiomas en los que son compatibles. Si no sabes por qué deberían usarse en algún lugar, no deberían serlo.

Editar: para aclarar, hay dos razones principales por las que deben usarse con moderación:

  1. Es fácil hacer binarios masivos usando inline en casos donde no es necesario
  2. El comstackdor tiende a saber mejor que usted cuando algo debería, desde el punto de vista del rendimiento, estar en línea

Lo mejor es dejar las cosas en paz y dejar que el comstackdor haga su trabajo, luego perfile y descubra si la mejor solución es en línea. Por supuesto, algunas cosas simplemente tienen sentido para estar incluidas (en particular, los operadores matemáticos), pero dejar que el comstackdor lo maneje suele ser la mejor práctica.

Actualización: por la respuesta de konrad.kruczynski , lo siguiente es cierto para las versiones de .NET hasta e incluyendo 4.0.

Puede usar la clase MethodImplAttribute para evitar que un método esté en línea …

 [MethodImpl(MethodImplOptions.NoInlining)] void SomeMethod() { // ... } 

… pero no hay forma de hacer lo opuesto y forzarlo a que esté alineado.

Estás mezclando dos conceptos separados. La función inline es una optimización del comstackdor que no tiene ningún impacto en la semántica. Una función se comporta igual si está en línea o no.

Por otro lado, las funciones lambda son puramente un concepto semántico. No existe un requisito sobre cómo deben implementarse o ejecutarse, siempre que sigan el comportamiento establecido en la especificación del idioma. Pueden incluirse si el comstackdor JIT lo desea, o no si no lo hace.

No existe una palabra clave en línea en C #, porque es una optimización que generalmente se puede dejar al comstackdor, especialmente en los idiomas JIT. El comstackdor JIT tiene acceso a las estadísticas de tiempo de ejecución, lo que le permite decidir qué alinear de manera mucho más eficiente de lo que puede hacerlo al escribir el código. Una función estará en línea si el comstackdor decide hacerlo, y no hay nada que pueda hacer al respecto de cualquier manera. 🙂

¿Te refieres a funciones en línea en el sentido de C ++? ¿En qué los contenidos de una función normal se copian automáticamente en línea en el callsite? El efecto final es que no ocurre ninguna llamada de función cuando se llama a una función.

Ejemplo:

 inline int Add(int left, int right) { return left + right; } 

Si es así, entonces no, no hay C # equivalente a esto.

¿O te refieres a funciones que están declaradas dentro de otra función? Si es así, entonces sí, C # lo admite a través de métodos anónimos o expresiones lambda.

Ejemplo:

 static void Example() { Func add = (x,y) => x + y; var result = add(4,6); // 10 } 

Cody tiene razón, pero quiero dar un ejemplo de lo que es una función en línea.

Digamos que tienes este código:

 private void OutputItem(string x) { Console.WriteLine(x); //maybe encapsulate additional logic to decide // whether to also write the message to Trace or a log file } public IList BuildListAndOutput(IEnumerable x) { // let's pretend IEnumerable.ToList() doesn't exist for the moment IList result = new List(); foreach(string y in x) { result.Add(y); OutputItem(y); } return result; } 

El optimizador Just-In-Time del comstackdor podría elegir alterar el código para evitar colocar repetidamente una llamada a OutputItem () en la stack, de modo que sería como si hubiera escrito el siguiente código:

 public IList BuildListAndOutput(IEnumerable x) { IList result = new List(); foreach(string y in x) { result.Add(y); // full OutputItem() implementation is placed here Console.WriteLine(y); } return result; } 

En este caso, diríamos que la función OutputItem () estaba en línea. Tenga en cuenta que podría hacer esto incluso si también se llama al OutputItem () desde otros lugares.

Editado para mostrar un escenario más probable que esté en línea.

Sí Exactamente, la única distinción es el hecho de que devuelve un valor.

Simplificación (sin usar expresiones):

List.ForEach Toma una acción, no espera un resultado de retorno.

Entonces un delegado de Action sería suficiente … decir:

 List.ForEach(param => Console.WriteLine(param)); 

es lo mismo que decir:

 List.ForEach(delegate(T param) { Console.WriteLine(param); }); 

la diferencia es que el tipo de param y la declinación del delegado se deducen por el uso y las llaves no son necesarias en un método simple en línea.

Donde como

List.Where Toma una función, esperando un resultado.

Entonces se esperaría una Function :

 List.Where(param => param.Value == SomeExpectedComparison); 

que es lo mismo que:

 List.Where(delegate(T param) { return param.Value == SomeExpectedComparison; }); 

También puede declarar estos métodos en línea y asignarlos a las variables IE:

 Action myAction = () => Console.WriteLine("I'm doing something Nifty!"); myAction(); 

o

 Function myFunction = theObject => theObject.ToString(); string myString = myFunction(someObject); 

Espero que esto ayude.

Hay ocasiones en las que deseo obligar al código a alinearse.

Por ejemplo, si tengo una rutina compleja en la que hay una gran cantidad de decisiones tomadas dentro de un bloque altamente iterativo y esas decisiones dan como resultado acciones similares pero levemente diferentes a llevar a cabo. Consideremos por ejemplo, un comparador de ordenamiento complejo (no impulsado por BD) donde el algoritmo de clasificación ordena los elementos de acuerdo con una serie de criterios diferentes no relacionados, como uno podría hacer si estuvieran clasificando palabras de acuerdo con criterios gtwigticales y semánticos para un lenguaje rápido sistema de reconocimiento. Tiendo a escribir funciones de ayuda para manejar esas acciones a fin de mantener la legibilidad y la modularidad del código fuente.

Sé que esas funciones de ayuda deberían estar alineadas porque esa es la forma en que se escribiría el código si nunca hubiera tenido que ser entendido por un humano. Ciertamente, me gustaría asegurarme en este caso de que no haya una función que llame la sobrecarga.

La afirmación “es mejor dejar estas cosas en paz y dejar que el comstackdor haga el trabajo …” (Cody Brocious) es completo. He estado progtwigndo código de juego de alto rendimiento durante 20 años, y todavía tengo que encontrarme con un comstackdor que sea lo suficientemente inteligente como para saber qué código debe incluirse (funciones) o no. Sería útil tener una statement “en línea” en c #, la verdad es que el comstackdor simplemente no tiene toda la información que necesita para determinar qué función debe estar siempre en línea o no sin la pista “en línea”. Claro, si la función es pequeña (acceso), entonces podría estar automáticamente en línea, pero ¿qué pasa si se trata de unas pocas líneas de código? Nonesense, el comstackdor no tiene forma de saber, no puedes dejar eso al comstackdor para obtener un código optimizado (más allá de los algoritmos).

No, no existe tal construcción en C #, pero el comstackdor .NET JIT podría decidir hacer llamadas de función en línea en el tiempo de JIT. Pero en realidad no sé si realmente está haciendo esas optimizaciones.
(Creo que debería :-))

En caso de que sus ensamblajes sean ngen-ed, es posible que desee echarle un vistazo a TargetedPatchingOptOut. Esto ayudará a ngen a decidir si aplicar métodos en línea. Referencia de MSDN

Sin embargo, todavía es solo una sugerencia declarativa para optimizar, no un comando imperativo.

Sé que esta pregunta es sobre C #. Sin embargo, puede escribir funciones en línea en .NET con F #. ver: uso de `inline` en F #

C # no admite métodos en línea (o funciones) en la forma en que los lenguajes dynamics como Python lo hacen. Sin embargo, los métodos anónimos y lambdas se pueden usar para fines similares, incluso cuando necesita acceder a una variable en el método contenedor como en el ejemplo a continuación.

 static void Main(string[] args) { int a = 1; Action inline = () => a++; inline(); //here a = 2 } 

¡Las expresiones Lambda son funciones en línea! ¡Creo que C # no tiene un atributo adicional como inline o algo así!