Fonctions Inline en C#?
Comment faites-vous à "fonctions inline" en C#? Je ne crois pas comprendre le concept. Ce sont des méthodes anonymes? Comme les fonctions lambda?
Note : les réponses traitent presque entièrement de la capacité de fonctions en ligne , c.-à-d. " une optimisation manuelle ou de compilateur qui remplace une fonction Appel site avec le corps de l'appel."Si vous êtes intéressés à anonyme (un.k.un. lambda) fonctions , voir la réponse de @jalf ou Qu'est-ce que cette "Lambda" dont tout le monde parle? .
14 réponses
enfin dans .NET 4.5, le CLR permet d'indiquer/suggérer 1 méthode en ligne en utilisant MethodImplOptions.AggressiveInlining
valeur. Il est également disponible dans le coffre du Mono (committed today).
// 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é ici. Puisqu'il y a eu quelques remarques négatives, je vais essayer de clarifier le terme. Comme dans les commentaires et la documentation, The method should be inlined if possible.
en particulier compte tenu de Mono (qui est ouvert), il y a certaines limitations techniques monospécifiques qui tiennent compte de la stabilité ou plus générales (comme les fonctions virtuelles). Dans l'ensemble, oui, c'est une indication pour le compilateur, mais je suppose que c'est ce qui a été demandé.
méthodes Inline sont simplement une optimisation de compilateur où le code d'une fonction est roulé dans l'appelant.
il n'y a aucun mécanisme pour 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.
Éditer: pour clarifier, Il ya deux principales raisons, ils doivent être utilisés avec parcimonie:
- il est facile de faites des binaires massifs en utilisant inline dans les cas où ce n'est pas nécessaire
- le compilateur a tendance à savoir mieux que vous quand quelque chose devrait, du point de vue de la performance, être intitulé
il est préférable de laisser les choses en paix et de laisser le compilateur faire son travail, puis de déterminer si inline est la meilleure solution pour vous. Bien sûr, certaines choses ne sens inline (opérateurs mathématiques en particulier), mais en laissant la la manipulation du compilateur est typiquement la meilleure pratique.
mise à Jour: Par konrad.la réponse de kruczynski , ce qui suit est vrai pour les versions de .NET jusqu'à et y compris 4.0.
vous pouvez utiliser la classe de la méthode" MethodImplAttribute à empêcher une méthode d'être inlined...
[MethodImpl(MethodImplOptions.NoInlining)]
void SomeMethod()
{
// ...
}
...mais il n'y a aucun moyen de faire le contraire et force afin qu'il soit incorporé.
vous mélangez deux concepts distincts. La fonction inlining est une optimisation du compilateur qui n'a aucun impact sur la sémantique. Une fonction se comporte de la même façon qu'elle soit inlinée ou non.
d'autre part, les fonctions lambda sont un concept purement sémantique. Il n'y a aucune exigence sur la façon dont ils devraient être mis en œuvre ou exécutés, tant qu'ils suivent le comportement énoncé dans la spécification de la langue. Ils peuvent être inlined si le compilateur JIT en a envie, ou pas s'il Non.
il n'y a pas de mot clé en ligne dans C#, parce que c'est une optimisation qui peut généralement être laissée au compilateur, en particulier dans les langues JIT'ed. Le compilateur JIT a accès à des statistiques d'exécution, ce qui lui permet de décider quoi mettre en ligne beaucoup plus efficacement que vous ne le pouvez en écrivant le code. Une fonction sera inlined si le compilateur le décide, et il n'y a rien que vous puissiez faire de toute façon. :)
voulez-vous dire des fonctions inline au sens C++? Dans lequel le contenu d'une fonction normale est automatiquement copié en ligne dans le callsite? 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 oui, alors non, il n'y a pas de C# équivalent à cela.
ou voulez-vous dire des fonctions qui sont déclarées dans une autre fonction? Si c'est le cas, alors oui, c# soutiens 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
}
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 compilateur Just-In-Time optimizer pourrait choisir de modifier le code pour éviter de placer à plusieurs reprises un appel à OutputItem () sur la pile, de sorte que ce serait comme si vous aviez écrit le code comme ceci à la place:
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 le La fonction OutputItem () a été supprimée. Notez qu'il peut le faire même si L'OutputItem() est appelé d'autres endroits aussi.
édité pour montrer un scénario plus-susceptible d'être inlined.
Oui, Exactement, la seule distinction est le fait qu'elle renvoie une valeur.
Simplification (sans expressions):
List<T>.ForEach
prend une mesure, il ne s'attend pas à un résultat de retour.
donc un délégué Action<T>
suffirait.. dis:
List<T>.ForEach(param => Console.WriteLine(param));
est la même chose que dire:
List<T>.ForEach(delegate(T param) { Console.WriteLine(param); });
la différence est que le type param et la déclération déléguée sont déduits par l'usage et les entretoises ne sont pas nécessaires sur une méthode simple en ligne.
Où
List<T>.Where
prend une fonction, 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 inscrire aux 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 aidera.
il y a des occasions où je souhaite forcer le code à être intégré.
par exemple, si j'ai une routine complexe où il y a un grand nombre de décisions prises dans un bloc très itératif et que ces décisions donnent lieu à des actions similaires mais légèrement différentes à mener. Par exemple, un comparateur de tri complexe (non piloté par la base de données) où l'algorithme de tri trie les éléments en fonction d'un certain nombre de critères différents tels qu'un pourrait faites - le s'ils trient les mots selon des critères grammatiques et sémantiques pour un système de reconnaissance linguistique rapide. J'aurais tendance à écrire des fonctions d'aide 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 parce que c'est la façon dont le code serait écrit s'il n'avait jamais à être compris par un humain. Je tiens certainement pour s'assurer dans ce cas que étaient pas Fonction appel au-dessus.
La déclaration "de son mieux pour laisser ces choses seul et laisser le compilateur faire le travail.."(Cody Brocious) est un rubish complet. J'ai programmé 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 inlined (functions) ou non. Il serait utile d'avoir une déclaration "inline" dans c#, la vérité est que le compilateur n'a tout simplement pas toutes les informations dont il a besoin pour déterminer quelle fonction devrait être toujours inlined ou pas sans l'indication "inline". Bien sûr, si la fonction est petite (accessor), alors elle pourrait être automatiquement inlined, mais qu'en est-il si c'est quelques lignes de code? Nonesense, le compilateur n'a aucun moyen de savoir, vous ne pouvez pas laisser cela au compilateur pour du code optimisé (au-delà des algorithmes).
Non, il n'y a pas de telle construction dans C#, mais le compilateur.net JIT pourrait décider de faire des appels de fonction en ligne sur le temps JIT. Mais en fait, je ne sais pas s'il fait vraiment de telles optimisations.
(je pense qu'il devrait :-))
dans le cas où vos assemblages seront ngen-ed, vous pourriez vouloir jeter un oeil à TargetedPatchingOptOut. Cela aidera le ngen à décider s'il faut utiliser des méthodes inline. référence MSDN
ce n'est encore qu'une indication déclarative pour optimiser, pas une commande impérative.
je sais que cette question concerne C#. Cependant, vous pouvez écrire des fonctions en ligne dans .NET avec F#. voir: utilisation de "inline` dans F#
C# ne supporte pas les méthodes (ou les fonctions) en ligne comme le font les langages dynamiques comme python. Cependant, les méthodes anonymes et lambdas peuvent être utilisées à des fins similaires, y compris lorsque vous avez besoin d'accéder à une variable dans la méthode contenant comme dans l'exemple ci-dessous.
static void Main(string[] args)
{
int a = 1;
Action inline = () => a++;
inline();
//here a = 2
}
les expressions Lambda sont des fonctions inline! Je pense que C# n'a pas d'attribut supplémentaire comme inline ou quelque chose comme ça!