如何在C#中制作内联函数


97

我正在使用Linq To XML

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

但我想在将前缀添加到xml之前对其进行一些计算,例如消除空格,特殊字符,进行一些计算等

我不想创建函数,因为这些函数对程序的任何其他部分都没有帮助,但是这有什么办法创建内联函数吗?


5
不要仅仅因为不会从任何其他地方调用它而禁止自己创建一个函数。函数也可以用于清理代码(如果您有一个跨多个页面的大型程序,将其分成多个函数使其更具可读性)和自我文档(仅适当命名一个函数即可将信息传达给阅读器。)
Joe

14
如果您来自Google,并且想知道如何在c#中模拟内联函数,请访问以下网址stackoverflow.com/questions/473782/inline-functions-in-c 以下答案与“内联”函数无关从字面上看,C#甚至没有真正的内联函数,但是上面的链接提供了可以使用的编译器优化。
JamesHoux

谢谢詹姆斯,问题标题确实的确令人误解。
Zar Shardan '18年

Answers:


226

是的,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!");
    }
    
  • Lambda是C#3.0中的新功能,有两种形式。

    • 表达式lambdas:

      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
      
    • 声明lambda:

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

基本上有两种不同的类型:FuncActionFunc的返回值,但Action不。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.使用内联函数时,您通常需要编写更少的代码
Volodymyr

35

C#7添加了对本地功能的支持

这是先前使用本地函数的示例

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

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

29

问题的答案是“是”和“否”,具体取决于您所说的“内联函数”的含义。如果您使用的术语类似于在C ++开发中使用的术语,那么答案是否定的,您不能这样做-即使是lambda表达式也是函数调用。确实可以定义内联lambda表达式来替换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
这是内联C#函数的Google热门歌曲。您说“也许每秒要调用数千次”,然后猜猜是什么-我每秒要调用400万次,所以是的...内联可能很有用(并且大大提高了代码的可读性我将要做的是:在16个位置手动展开一项功能。
亚当

17

是。

您可以创建匿名方法lambda表达式

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

谢谢您的回答,您能否再详细说明一下,兰巴舞,我的意思是codeFunc <string,string> PrefixTrimmer = x => x ???“”; code我是新来的人,我真的不太了解MSDN文档
Joe Dixon

2
@Joe:x ?? ""是null运算符。 msdn.microsoft.com/zh-CN/library/ms173224.aspx
SLaks 2011年

在中x => (something)x是一个参数,并且(something)是返回值`。
SLaks 2011年


2
@Hellfrost:阅读问题。他不是在问C ++风格的内联函数。我不想创建函数,因为这些函数对程序的任何其他部分都没有任何帮助,但这
SLaks 2011年

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);
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.