如何在C#中创建内联函数

时间:2011-02-04 16:03:08

标签: c# .net

我正在使用Linq To XML

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

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

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

6 个答案:

答案 0 :(得分:171)

是的,C#支持这一点。有几种语法可供使用。

    在C#2.0中添加了
  • Anonymous methods

    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是C#3.0中的新功能,有两种版本。

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

      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中引入了
  • Local functions

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

这些基本上有两种不同的类型:FuncActionFunc的返回值,但Action s不返回。 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.

答案 1 :(得分:19)

C#7增加了对local functions

的支持

以下是使用本地函数的前一个示例

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

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

答案 2 :(得分:18)

您的问题的答案是肯定而不是,取决于您对“内联函数”的含义。如果您正在使用C ++开发中使用的术语,那么答案是否定的,您不能这样做 - 即使lambda表达式是一个函数调用。虽然你可以定义内联lambda表达式来替换C#中的函数声明,但编译器仍然最终会创建一个匿名函数。

这是我用来测试它的一些非常简单的代码(VS2015):

<template name="emotis">
  {{{ parseEmoticons }}}
</template>

<template name="chat_page">
    <h2>Type in the box below to send a message!</h2>
  <div class="row">
    <div class="col-md-12">
      <div class="well well-lg">
        {{#each messages}}
          {{> chat_message}}
        {{/each}}
      </div>
    </div>
  </div>
  <div class="row">
    <div class="col-xs-12 col-sm-6 col-sm-offset-3">
      <form class="js-send-chat">  
        <div class="form-group">  
          <input class="form-control" id="input-emoticon" type="text" name="chat" placeholder="type a message here..." />
        </div>
        <button class="btn btn-primary btn-block">Send</button>
      </form>
    </div>
  </div>
</template>

<template name="chat_message">
  <div class="row">
    <div class="col-md-12">
      <span class=avatar> <img src="/{{creatorAvatar sentBy}}" class="creatorImg"> </span>
      <span class="text">On {{timeStamp}} </span>
      <span class="bold">{{getUserById sentBy}} said: {{{parseEmoticons text}}} </span>
    </div>
  </div>
<br>
<br>
</template>

编译器生成什么?我使用了一个名为ILSpy的漂亮工具来显示生成的实际IL程序集。看看(我省略了很多类设置)

这是主要功能:

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

请参阅IL_0026和IL_0027这些行?这两条指令加载数字5并调用一个函数。然后IL_0031和IL_0036格式化并打印结果。

这是一个名为:

的函数
        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

这是一个非常短的功能,但它是一个功能。

这值得优化吗?罗。也许如果你每秒调用它数千次,但如果性能如此重要,那么你应该考虑调用用C / C ++编写的本机代码来完成工作。

根据我的经验,可读性和可维护性几乎总是比优化速度增加几微秒更重要。使用函数使代码可读并控制变量作用域,而不用担心性能。

“过早优化是编程中所有邪恶(或至少大部分)的根源。” - 唐纳德克努特

“无法正常运行的程序无需快速运行” - 我

答案 3 :(得分:16)

您可以创建anonymous methodslambda expressions

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

答案 4 :(得分:5)

您可以使用Func封装一个具有一个参数的方法,并返回由TResult参数指定的类型的值。

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


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

答案 5 :(得分:1)

不仅是Inside方法,它也可以在类内部使用。

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