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


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

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

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

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

6 60

6 ответов:

да, 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 возвращаемые значения, но Actionне. Последний параметр типа Func - это тип возвращаемого значения; все остальные типы параметров.

есть похожие типы с разными именами, но синтаксис для объявления их inline одинаковый. Примером этого является 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.

да.

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

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

ответ на ваш вопрос-да и нет, в зависимости от того, что вы подразумеваете под "встроенной функцией". Если вы используете этот термин, как он используется в разработке на 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++, чтобы выполнить эту работу.

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

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

" программа, которая не работает правильно, не должна работать быстро" -- Я

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

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

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

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

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

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


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

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

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