web-dev-qa-db-fra.com

Fonctions en ligne en C #?

Comment faites-vous des "fonctions inline" en C #? Je ne pense pas comprendre le concept. Sont-ils comme des méthodes anonymes? Vous aimez les fonctions lambda?

Note : Les réponses traitent presque entièrement de la capacité de fonctions en ligne , c’est-à-dire "une optimisation manuelle ou par un compilateur qui remplace une fonction appelez le site avec le corps de l'appelé. " Si vous êtes intéressé par fonctions anonymes (a.k.a. lambda) , voir réponse de @ jalf ou Quel est ce 'Lambda' dont tout le monde parle? .

256
Dinah

Enfin, dans .NET 4.5, le CLR permet de suggérer/suggérer1 méthode en ligne utilisant MethodImplOptions.AggressiveInlining valeur. Il est également disponible dans le coffre du Mono (validé aujourd'hui).

_// 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 . Auparavant, "force" était utilisée ici. Puisqu'il y a eu quelques votes négatifs, je vais essayer de clarifier le terme. Comme dans les commentaires et la documentation, _The method should be inlined if possible._ Particulièrement en considérant Mono (qui est ouvert), il existe certaines limitations techniques mono-spécifiques en considérant l’inline ou des restrictions plus générales (comme les fonctions virtuelles). Dans l’ensemble, oui, c’est un indice pour le compilateur, mais je suppose que c’est ce qui a été demandé.

364
konrad.kruczynski

Les méthodes en ligne sont simplement une optimisation du compilateur dans laquelle le code d'une fonction est intégré à l'appelant.

Il n'y a pas de mécanisme permettant de faire cela en C #, et ils doivent être utilisés avec parcimonie dans les langues où ils sont supportés - si vous ne savez pas pourquoi ils devraient être utilisés quelque part, ils ne devraient pas l'être.

Edit: Pour clarifier, il y a deux raisons principales pour lesquelles ils doivent être utilisés avec parcimonie:

  1. Il est facile de créer des fichiers binaires massifs en utilisant inline dans les cas où cela n'est pas nécessaire.
  2. Le compilateur a tendance à savoir mieux que vous quand quelque chose devrait, du point de vue de la performance, être en ligne

Il est préférable de laisser les choses tranquilles et de laisser le compilateur faire son travail, puis de profiler et de déterminer si la solution en ligne est la meilleure solution pour vous. Bien sûr, certaines choses ont simplement du sens d'être en ligne (les opérateurs mathématiques en particulier), mais laisser le compilateur les gérer est généralement la meilleure pratique.

83
Cody Brocious

Mise à jour: Pour réponse de konrad.kruczynski , ce qui suit est vrai pour les versions de .NET jusqu'à la version 4.0 incluse.

Vous pouvez utiliser le MethodImplAttribute class pour empêcher une méthode d'être en ligne ...

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

... mais il n'y a aucun moyen de faire l'inverse et l'oblige à le mettre en ligne.

50
BACON

Vous mélangez deux concepts distincts. Function inlining est une optimisation du compilateur qui n'a aucun impact sur la sémantique. Une fonction se comporte de la même manière, qu'elle soit en ligne ou non.

D'autre part, les fonctions lambda sont purement un concept sémantique. Il n'est pas nécessaire de savoir comment ils doivent être implémentés ou exécutés, à condition qu'ils suivent le comportement défini dans les spécifications de langage. Ils peuvent être en ligne si le compilateur JIT en a envie ou pas.

Il n'y a pas de mot-clé inline en C #, car c'est une optimisation qui peut généralement être laissée au compilateur, en particulier dans les langages JIT. Le compilateur JIT a accès aux statistiques d'exécution, ce qui lui permet de décider plus efficacement de la mise en ligne que vous ne le pouvez lors de l'écriture du code. Une fonction sera intégrée si le compilateur en décide ainsi et vous ne pouvez rien y faire. :)

32
jalf

Voulez-vous dire des fonctions en ligne au sens C++? Dans lequel le contenu d'une fonction normale est automatiquement copié en ligne sur le site d'appel? L'effet final étant qu'aucun appel de fonction ne se produit réellement lors de l'appel d'une fonction.

Exemple:

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

Si c'est le cas, non, il n'y a pas d'équivalent C # à ceci.

Ou voulez-vous dire des fonctions qui sont déclarées dans une autre fonction? Si c'est le cas, oui, C # prend en charge cela via des méthodes anonymes ou des expressions lambda.

Exemple:

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

Cody a raison, mais je veux donner un exemple de ce qu'est une fonction en ligne.

Disons que vous avez ce code:

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<string> BuildListAndOutput(IEnumerable<string> x)
{  // let's pretend IEnumerable<T>.ToList() doesn't exist for the moment
    IList<string> result = new List<string>();

    foreach(string y in x)
    {
        result.Add(y);
        OutputItem(y);
    }
    return result;
}

Le compilateurL’optimiseur Just-In-Time peut choisir de modifier le code pour éviter d’appeler à plusieurs reprises OutputItem () sur la pile, afin que ce soit comme si vous aviez écrit le code comme suit:

public IList<string> BuildListAndOutput(IEnumerable<string> x)
{
    IList<string> result = new List<string>();

    foreach(string y in x)
    {
        result.Add(y);

        // full OutputItem() implementation is placed here
        Console.WriteLine(y);   
    }

    return result;
}

Dans ce cas, nous dirions que la fonction OutputItem () était en ligne. Notez qu'il peut le faire même si OutputItem () est également appelé depuis d'autres emplacements.

Edité pour montrer un scénario plus susceptible d'être en ligne.

20
Joel Coehoorn

Oui Exactement, la seule distinction est le fait qu'il renvoie une valeur.

Simplification (sans utilisation d'expressions):

List<T>.ForEach Effectue une action, il n'attend pas de résultat.

Donc, un délégué Action<T> suffirait .. dites:

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

est la même chose que de dire:

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

la différence est que le type de paramètre et la décélération de délégué sont déduits par l'utilisation et que les accolades ne sont pas obligatoires pour une méthode simple en ligne.

Tandis que

List<T>.Where Prend une fonction et attend un résultat.

Donc, un Function<T, bool> serait attendu:

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

qui est le même que:

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

Vous pouvez également déclarer ces méthodes en ligne et les attribuer à des variables IE:

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

myAction();

ou

Function<object, string> myFunction = theObject => theObject.ToString();

string myString = myFunction(someObject);

J'espère que ça aide.

6
Quintin Robinson

L’affirmation "il est préférable de laisser ces choses de côté et de laisser le compilateur faire le travail .." (Cody Brocious) est complète. Je programme du code de jeu haute performance depuis 20 ans et je n’ai pas encore trouvé de compilateur "suffisamment intelligent" pour savoir quel code devrait être intégré (fonctions) ou non. Il serait utile d’avoir une déclaration "inline" en c #. En réalité, le compilateur ne dispose pas de toutes les informations nécessaires pour déterminer quelle fonction doit toujours être en ligne ou non sans le "inline". Bien sûr, si la fonction est petite (accesseur), elle sera peut-être automatiquement insérée, mais que se passera-t-il s'il ne s'agit que de quelques lignes de code? Nonesense, le compilateur n'a aucun moyen de savoir, vous ne pouvez pas laisser cela au compilateur pour un code optimisé (au-delà des algorithmes).

2
gvick2002

Il y a des occasions où je souhaite forcer le code à être aligné.

Par exemple, si j'ai une routine complexe dans laquelle un grand nombre de décisions sont prises dans un bloc hautement itératif et que ces décisions entraînent des actions similaires mais légèrement différentes. Considérons, par exemple, un comparateur de tri complexe (non piloté par DB) où l'algorithme de tri trie les éléments en fonction d'un certain nombre de critères différents, tels que ceux que l'on pourrait trier s'ils triaient des mots en fonction de critères grammaticaux et sémantiques pour un langage rapide. système de reconnaissance. J'aurais tendance à écrire des fonctions d'assistance pour gérer ces actions afin de maintenir la lisibilité et la modularité du code source.

Je sais que ces fonctions d’aide devraient être alignées, car c’est ainsi que le code serait écrit s’il n’avait jamais besoin d’être compris par un humain. Je voudrais certainement m'assurer dans ce cas qu'il n'y a pas de fonction appelant des frais généraux.

2
developer

Je sais que cette question concerne C #. Cependant, vous pouvez écrire des fonctions inline dans .NET avec F #. voir: tilisation de `inline` en F #

0
Goswin

Au cas où vos assemblages seraient génériques, vous pouvez jeter un oeil à TargetedPatchingOptOut. Cela aidera ngen à décider s'il convient d'utiliser des méthodes en ligne. référence MSDN

Il ne s'agit toujours que d'un indice déclaratif à optimiser, pas d'une commande impérative.

0
Tim Lovell-Smith

Non, il n'y a pas de telle construction en C #, mais le compilateur .NET JIT pourrait décider de faire des appels de fonction en ligne le temps de JIT. Mais en réalité, je ne sais pas si nous procédons réellement à de telles optimisations.
(Je pense que ça devrait :-))

0
mmmmmmmm