Как создавать встроенные функции на C #


98

Я использую Linq To XML

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

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

Я не хочу создавать функции, потому что они не помогут ни в какой другой части моей программы, кроме этой, так есть ли способ создавать встроенные функции?


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

14
Если вы пришли сюда из Google и хотите узнать, как имитировать встроенные функции в C #, перейдите сюда: stackoverflow.com/questions/473782/inline-functions-in-c Ответы ниже не относятся к "встроенным" функциям. в истинном смысле этого слова, а в C # даже нет настоящих встроенных функций, но приведенная выше ссылка обеспечивает оптимизацию компилятора, которую можно использовать.
— JamesHoux

Спасибо, Джеймс, название вопроса действительно вводит в заблуждение.
— Зар Шардан

Ответы:


228

Да, C # это поддерживает. Доступно несколько синтаксисов.

  • Анонимные методы были добавлены в C # 2.0:

    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!");
    }
    
  • Лямбда-выражения появились в C # 3.0 и представлены в двух вариантах.

    • Лямбды выражений:

      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
      
    • Лямбды операторов:

      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; };
      
  • В C # 7.0 появились локальные функции :

    int add(int x, int y) => x + y;
    void print(int x) { Console.WriteLine(x); }
    

Они бывают двух основных типов: Funcи Action. Funcs возвращает значения, а Actions - нет. Последний параметр типа a Func- это возвращаемый тип; все остальные - это типы параметров.

Существуют похожие типы с разными именами, но синтаксис для объявления их встроенными одинаков. Примером этого является Comparison<T>, что примерно эквивалентно 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.0 onwards

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

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

4
Я не понимаю этого ответа. В его примере он хочет, чтобы новый XElement («Prefix», prefix => newPrefix) был объявлен встроенным. Все эти ответы сводятся к объявлению новой функции. Почему бы просто не объявить новую функцию?
— Мэтью Джеймс Дэвис

3
потому что: 1. понять логику метода чтения встроенных функций намного проще, чем искать разные объявления 2. часто вам нужно писать меньше кода при использовании встроенных функций
— Владимир

35

C # 7 добавляет поддержку локальных функций

Вот предыдущий пример с использованием локальной функции

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

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

29

Ответ на ваш вопрос - да или нет, в зависимости от того, что вы подразумеваете под «встроенной функцией». Если вы используете термин так, как он используется в разработке на C ++, тогда ответ будет отрицательным, вы не можете этого сделать - даже лямбда-выражение является вызовом функции. Хотя верно то, что вы можете определять встроенные лямбда-выражения для замены объявлений функций в C #, компилятор все равно создает анонимную функцию.

Вот действительно простой код, который я использовал для тестирования (VS2015):

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

Что генерирует компилятор? Я использовал отличный инструмент под названием ILSpy, который показывает фактическую сгенерированную сборку IL. Посмотрите (я пропустил много вещей по настройке классов)

Это основная функция:

        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

Видите эти строки IL_0026 и IL_0027? Эти две инструкции загружают число 5 и вызывают функцию. Затем отформатируйте IL_0031 и IL_0036 и распечатайте результат.

И вот функция, которая называется:

        .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'

Это действительно короткая функция, но это функция.

Стоит ли прилагать усилия для оптимизации? Неа. Возможно, если вы вызываете его тысячи раз в секунду, но если производительность так важна, вам следует подумать о вызове собственного кода, написанного на C / C ++, для выполнения работы.

По моему опыту, удобочитаемость и ремонтопригодность почти всегда важнее, чем оптимизация для увеличения скорости на несколько микросекунд. Используйте функции, чтобы сделать ваш код читабельным, контролировать область видимости переменных и не беспокоиться о производительности.

«Преждевременная оптимизация - это корень всего зла (или, по крайней мере, большей его части) в программировании». - Дональд Кнут

«Программа, которая работает некорректно, не должна работать быстро» - Я


3
Это лучший хит Google по встраиванию функций C #. Вы говорите: «Может быть, если вы вызываете это тысячи раз в секунду», и угадайте, что - я называю это 4 миллиона раз в секунду, так что да ... встраивание, вероятно, было бы полезно (и значительно повысило бы читаемость кода по сравнению с тем, что Придется сделать: ручное развертывание одной функции в 16 местах).
— Adam

17

Да.

Вы можете создавать анонимные методы или лямбда-выражения :

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

Спасибо за ответ, не могли бы вы подробнее рассказать об ответе, ламба, я имею в виду codeFunc <string, string> PrefixTrimmer = x => x ?? ""; codeЯ новичок в этом, и я действительно не очень хорошо понимаю документ MSDN
— Джо Диксон

2
@Joe: x ?? ""оператор объединения с нулем. msdn.microsoft.com/en-us/library/ms173224.aspx
— SLaks

В x => (something), xявляется параметром, и (something)это возвращение value`.
— SLaks


2
@Hellfrost: Прочтите вопрос. Он не спрашивает о встроенных функциях в стиле C ++. Я не хочу создавать функции, потому что они не помогут ни в какой другой части моей программы, кроме этой
— SLaks

5

Вы можете использовать Func, который инкапсулирует метод с одним параметром и возвращает значение типа, указанного параметром TResult.

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


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

4

Не только внутри методов, но и внутри классов.

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);
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.