C #에서 인라인 함수를 만드는 방법


99

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

James에게 감사합니다. 질문 제목은 실제로 오해의 소지가 있습니다.
Zar Shardan

답변:


230

예, 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의 새로운 기능이며 두 가지 유형으로 제공됩니다.

    • 식 람다 :

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

이 이러한 두 가지 종류가 기본적으로 있습니다 : FuncAction. Funcs는 값을 반환하지만 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
이 대답을 이해하지 못합니다. 그의 예에서 그는 인라인으로 선언 된 new XElement ( "Prefix", prefix => newPrefix)를 원합니다. 이 모든 대답은 새로운 함수를 선언하는 것과 같습니다. 새 함수를 선언하지 않는 이유는 무엇입니까?
Matthew James Davis

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

30

귀하의 질문에 대한 대답은 "인라인 기능"이 의미하는 바에 따라 예 및 아니오입니다. C ++ 개발에서 사용되는 것과 같은 용어를 사용하는 경우 대답은 아니오입니다. 그렇게 할 수 없습니다. 심지어 람다 식도 함수 호출입니다. C #에서 함수 선언을 대체하기 위해 인라인 람다 식을 정의 할 수 있다는 것은 사실이지만 컴파일러는 여전히 익명 함수를 생성합니다.

다음은 이것을 테스트하는 데 사용한 매우 간단한 코드입니다 (VS2015).

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

컴파일러는 무엇을 생성합니까? 실제로 생성 된 IL 어셈블리를 보여주는 ILSpy라는 멋진 도구를 사용했습니다. 보세요 (많은 수업 설정 항목을 생략했습니다)

이것이 주요 기능입니다.

        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'

정말 짧은 기능이지만 기능입니다.

최적화를 위해 노력할 가치가 있습니까? 아니. 1 초에 수천 번 호출하고 있지만 성능이 그렇게 중요하다면 C / C ++로 작성된 네이티브 코드를 호출하여 작업을 수행하는 것을 고려해야합니다.

내 경험상 가독성과 유지 보수성은 몇 마이크로 초의 속도 향상을 최적화하는 것보다 거의 항상 더 중요합니다. 함수를 사용하여 코드를 읽기 쉽게 만들고 변수 범위를 제어하고 성능에 대해 걱정하지 마십시오.

"조기 최적화는 프로그래밍에서 모든 악 (또는 적어도 대부분)의 근원입니다." -도널드 크 누스

"올바르게 실행되지 않는 프로그램은 빠르게 실행할 필요가 없습니다."-Me


4
이것은 C # 함수를 인라인하는 Google 최고의 히트작입니다. "초당 수천 번 호출한다면 아마도"라고 말하고 무엇을 추측 할 수 있는지 추측 해보십시오. 1 초에 400 만 번 호출하고 있습니다. 그러니 인라인이 유용 할 것입니다. 내가해야 할 일 : 16 개 위치에서 하나의 기능을 수동으로 풀기).
아담

Kotlin에 익숙한 사용자에게는 Kotlin의 inline함수가 C #에 해당하는 기능이 없음을 의미합니다 .
Vapid Linus

17

예.

익명 메서드 또는 람다 식을 만들 수 있습니다 .

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

답변 해 주셔서 감사합니다. 답변에 대해 좀 더 자세히 code설명해 주시겠습니까? 람바 하나, Func <string, string> PrefixTrimmer = x => x ?? ""; code이 새로운 메신저와 나는 MSDN 문서를 잘 이해하지 못한다
Joe Dixon

2
@Joe : x ?? ""는 null 통합 연산자입니다. msdn.microsoft.com/en-us/library/ms173224.aspx
SLaks

에서은 x => (something), x매개 변수이며, (something)반환 값 '이다.
SLaks


2
@Hellfrost : 질문을 읽어보세요. 그는 C ++ 스타일의 인라인 함수에 대해 묻지 않습니다. 나는이 사람이 내 프로그램의 다른 부분에 어떤 도움이 될 수 없기 때문에 기능을 만들려하지만,이되지 않습니다
SLaks

5

하나의 매개 변수가있는 메소드를 캡슐화하고 TResult 매개 변수에 지정된 유형의 값을 리턴하는 Func 를 사용할 수 있습니다 .

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


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

4

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);
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.