Как сделать встроенные функции в С#
Я использую Linq To XML
new XElement("Prefix", Prefix == null ? "" : Prefix)
но я хочу сделать некоторые вычисления для префикса, прежде чем добавлять его в xml, например, исключая пробелы, специальные символы, некоторые вычисления и т.д.
Я не хочу создавать функции, потому что они не будут помогать ни в какой другой части моей программы, но это так, и есть ли способ создать встроенные функции?
Ответы
Ответ 1
Да, С# поддерживает это. Доступно несколько синтаксисов:
-
Анонимные методы (доступны с С# 2 и далее)
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!");
}
-
Выражение Lambdas (доступно с С# 3 и далее)
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
-
Заявление lambdas (доступно с С# 3 и далее)
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; };
Для них существуют два разных типа: Func
и Action
. Func
возвращать значения, но 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 onwards
Они могут быть вызваны напрямую, как если бы они были обычными методами:
int x = add(23,17); // x == 40
print(x); // outputs 40
helloWorld(x); // helloWord has one int parameter declared: Action<int>
// even though it does not make any use of it.
Ответ 2
Да.
Вы можете создать анонимные методы или лямбда-выражения:
Func<string, string> PrefixTrimmer = delegate(string x) {
return x ?? "";
};
Func<string, string> PrefixTrimmer = x => x ?? "";
Ответ 3
Ответ на ваш вопрос - да и нет, в зависимости от того, что вы подразумеваете под "встроенной функцией". Если вы используете термин, как он используется в разработке на С++, тогда ответ будет отрицательным, вы не можете этого сделать - даже выражение лямбда - это вызов функции. Хотя верно, что вы можете определять встроенные лямбда-выражения для замены деклараций функций в С#, компилятор все равно заканчивает создание анонимной функции.
Вот какой действительно простой код, который я использовал для тестирования этого (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/С++, для выполнения этой работы.
По моему опыту читаемость и ремонтопригодность почти всегда важнее оптимизации на несколько микросекунд в скорости. Используйте функции, чтобы сделать ваш код доступным для чтения и контролировать область видимости переменных и не беспокоиться о производительности.
"Преждевременная оптимизация - это корень всех злых (или, по крайней мере, большей части) в программировании".
- Дональд Кнут
"Программа, которая работает неправильно, не требует быстрого запуска"
- Me
Ответ 4
Вы можете использовать Func, который инкапсулирует метод с одним параметром и возвращает значение типа, заданного параметром TResult.
void Method()
{
Func<string,string> inlineFunction = source =>
{
// add your functionality here
return source ;
};
// call the inline function
inlineFunction("prefix");
}