Встроенные функции в C #? - PullRequest
       42

Встроенные функции в C #?

252 голосов
/ 23 января 2009

Как вы делаете "встроенные функции" в C #? Я не думаю, что понимаю концепцию. Они как анонимные методы? Как лямбда-функции?

Примечание : ответы почти полностью касаются возможности встроенных функций , т. Е. «Оптимизации вручную или компилятора, которая заменяет сайт вызова функции телом вызываемого». Если вас интересуют анонимные (a.k.a. лямбда) функции , см. @ ответ Джалфа или О чем все эти «лямбда» продолжают говорить?

Ответы [ 14 ]

358 голосов
/ 05 января 2012

Наконец, в .NET 4.5 CLR позволяет намекнуть / предложить метод 1 , используя значение MethodImplOptions.AggressiveInlining. Он также доступен в багажнике Mono (совершено сегодня).

// 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 . Ранее здесь использовалась «сила». Поскольку было несколько отрицательных голосов, я попытаюсь уточнить этот термин. Как и в комментариях и документации, The method should be inlined if possible. Особенно с учетом Mono (который открыт), существуют некоторые моно-специфические технические ограничения, касающиеся встраивания или более общие (например, виртуальные функции). В целом, да, это подсказка компилятору, но я думаю, это то, о чем просили.

83 голосов
/ 23 января 2009

Встроенные методы - это просто оптимизация компилятора, когда код функции свернут в вызывающую сторону.

Нет механизма, с помощью которого это можно сделать в C #, и они будут использоваться экономно в тех языках, где они поддерживаются - если вы не знаете, почему их нужно где-то использовать, их не должно быть. 1003 *

Редактировать: Чтобы уточнить, есть две основные причины, по которым их нужно использовать экономно:

  1. Легко создавать массивные двоичные файлы, используя inline, если в этом нет необходимости
  2. Компилятор, как правило, знает лучше, чем вы, когда что-то должно быть с точки зрения производительности встроено

Лучше оставить все в покое и позволить компилятору выполнить свою работу, а затем профилировать и выяснить, является ли inline лучшим решением для вас. Конечно, некоторые вещи имеют смысл встраивать (в частности, в математические операторы), но, как правило, использование компилятора является лучшей практикой.

50 голосов
/ 17 января 2010

Обновление: За ответ konrad.kruczynski , верно следующее для версий .NET до 4.0 включительно.

Вы можете использовать класс MethodImplAttribute до , предотвращающий метод inline ...

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

... но нет способа сделать обратное и принудительно сделать это внутри.

32 голосов
/ 23 января 2009

Вы смешиваете две разные концепции. Встраивание функций - это оптимизация компилятора, которая не влияет на семантику. Функция ведет себя одинаково независимо от того, встроена она или нет.

С другой стороны, лямбда-функции - это чисто семантическая концепция. Нет требований к тому, как они должны быть реализованы или выполнены, если они следуют поведению, изложенному в спецификации языка. Они могут быть встроены, если JIT-компилятор чувствует себя так, или нет, если это не так.

В C # нет встроенного ключевого слова, потому что это оптимизация, которую обычно можно оставить компилятору, особенно в языках JIT. JIT-компилятор имеет доступ к статистике времени выполнения, что позволяет ему решать, что встроить гораздо эффективнее, чем вы можете при написании кода. Функция будет встроена, если компилятор решит, и вы ничего не можете с этим поделать. :)

21 голосов
/ 23 января 2009

Вы имеете в виду встроенные функции в смысле C ++? В каком случае содержимое обычной функции автоматически копируется в строку вызова? Конечным эффектом является то, что при вызове функции не происходит никакого вызова функции.

Пример:

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

Если это так, то нет, C # не эквивалентно этому.

Или Вы имеете в виду функции, которые объявлены внутри другой функции? Если это так, то да, C # поддерживает это с помощью анонимных методов или лямбда-выражений.

Пример:

static void Example() {
  Func<int,int,int> add = (x,y) => x + y;
  var result = add(4,6);  // 10
}
20 голосов
/ 23 января 2009

У Коди все правильно, но я хочу привести пример того, что такое встроенная функция.

Допустим, у вас есть этот код:

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;
}

Компилятор Оптимизатор Just-In-Time может изменить код, чтобы избежать повторного вызова функции OutputItem () в стеке, так что это было бы так, как если бы вы написали код как это вместо:

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;
}

В этом случае мы бы сказали, что функция OutputItem () была встроенной. Обратите внимание, что это может быть сделано, даже если OutputItem () вызывается и из других мест.

Отредактировано, чтобы показать сценарий, который с большей вероятностью будет встроенным.

6 голосов
/ 23 января 2009

Да Точно, единственное различие заключается в том, что он возвращает значение.

Упрощение (без использования выражений):

List<T>.ForEach Выполняет действие, не ожидает возврата.

Так что делегата Action<T> будет достаточно .. скажем:

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

- это то же самое, что сказать:

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

Разница в том, что тип параметра и удаление делегата определяются с помощью использования, и для простого встроенного метода скобки не требуются.

Где, как

List<T>.Where Принимает функцию, ожидая результата.

Таким образом, можно ожидать Function<T, bool>:

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

, что совпадает с:

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

Вы также можете объявить эти методы встроенными и присвоить их переменным IE:

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

myAction();

или

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

string myString = myFunction(someObject);

Надеюсь, это поможет.

2 голосов
/ 05 марта 2011

Утверждение «лучше всего оставить все это в покое и позволить компилятору выполнить работу…» (Коди Брошиус) - полная чушь. Я программировал высокопроизводительный игровой код в течение 20 лет, и мне еще не приходилось сталкиваться с «достаточно умным» компилятором, чтобы знать, какой код должен быть встроен (функции) или нет. Было бы полезно иметь «встроенный» оператор в c #, правда в том, что компилятор просто не имеет всей информации, необходимой ему для определения, какая функция должна быть всегда встроенной или нет без подсказки «inline». Конечно, если функция маленькая (accessor), то она может быть автоматически вставлена, но что, если это несколько строк кода? Безусловно, компилятор не знает, вы не можете просто оставить это на усмотрение компилятора (кроме алгоритмов).

2 голосов
/ 30 июня 2010

В некоторых случаях я хочу, чтобы код был встроен.

Например, если у меня есть сложная процедура, в которой большое количество решений принимается в очень итеративном блоке, и эти решения приводят к аналогичным, но слегка отличающимся действиям, которые необходимо выполнить. Рассмотрим, например, комплексный (не управляемый DB) сортировщик сравнения, в котором алгоритм сортировки сортирует элементы по ряду различных несвязанных критериев, как, например, можно было бы сделать, если бы они сортировали слова по грамматическим и семантическим критериям для быстрого языка система распознавания. Я хотел бы написать вспомогательные функции для обработки этих действий, чтобы обеспечить удобочитаемость и модульность исходного кода.

Я знаю, что эти вспомогательные функции должны быть встроены, потому что именно так будет написан код, если он никогда не будет понят человеком. В этом случае я бы, конечно, хотел убедиться, что не было служебных вызовов.

0 голосов
/ 22 декабря 2012

Я знаю, что этот вопрос о C #. Тем не менее, вы можете написать встроенные функции в .NET с помощью F #. см .: Использование `inline` в F #

...