Func 란 무엇이며 언제 어떻게 사용합니까?


115

무엇 Func<>이며 무엇을 위해 사용됩니까?


4
특정 서명을 가진 대리인을위한 바로 가기 일뿐입니다. 아래 답변을 완전히 이해하려면 대표자를 이해해야합니다. ;-)
Theo Lenndorff

2
@Oded의 대답에서 그것은 말한다If you have a function that needs to return different types, depending on the parameters, you can use a Func delegate, specifying the return type.
LCJ

답변:


76

Func<T>형식의 일부 값을 반환하는 메서드에 대해 미리 정의 된 대리자 형식입니다 T.

즉,이 유형을 사용하여 일부 값을 반환하는 메서드를 참조 할 수 있습니다 T. 예

public static string GetMessage() { return "Hello world"; }

다음과 같이 참조 될 수 있습니다.

Func<string> f = GetMessage;

그러나 정적 단일 인수 함수를 나타낼 수도 있습니다 =)
Ark-kun

2
@ Ark-kun 아니, 맞지 않습니다. 의 정의는 Func<T>입니다 delegate TResult Func<out TResult>(). 인수가 없습니다. Func<T1, T2>하나의 인수를 취하는 함수입니다.
Brian Rasmussen 2014 년

4
아니, 맞아. static int OneArgFunc(this string i) { return 42; } Func<int> f = "foo".OneArgFunc;. =)
Ark-kun

1
그것은 특별한 확장 방법입니다.
Brian Rasmussen 2014 년

그것에 대한 유일한 특별한 점은 ExtensionCLR이 아닌 C # / VB.Net 컴파일러에서만 읽는 속성입니다. 기본적으로 인스턴스 메서드 (정적 함수와 달리)에는 숨겨진 0 번째 "this"매개 변수가 있습니다. 따라서 1 인수 인스턴스 메소드는 2 인수 정적 함수와 매우 유사합니다. 그런 다음 대상 객체와 함수 포인터 를 저장하는 델리게이트가 있습니다 . 대리자는 첫 번째 인수를 target에 저장할 수 있거나 저장 하지 않을 수 있습니다.
Ark-kun

87

자리 표시 자로 생각하십시오. 특정 패턴을 따르지만 특정 기능에 묶일 필요가없는 코드가있을 때 매우 유용 할 수 있습니다.

예를 들어 Enumerable.Select확장 방법을 고려하십시오 .

  • 패턴 이다 시퀀스의 모든 아이템, 즉 아이템 (예를 들어, 속성) 일부 값을 선택하고 다음 값으로 구성된 새로운 시퀀스를 생성합니다.
  • 자리 이다 실제로 시퀀스의 값을 가져 다소 선택기 기능은 상술.

이 방법은 Func<T, TResult>구체적인 기능 대신을 사용합니다. 이를 통해 위의 패턴이 적용되는 모든 컨텍스트에서 사용할 수 있습니다 .

예를 들어, 내가 a가 List<Person>있고 목록에있는 모든 사람의 이름 만 원한다고 가정합니다. 나는 이것을 할 수있다 :

var names = people.Select(p => p.Name);

또는 모든 사람 의 나이 를 원한다고 말합니다.

var ages = people.Select(p => p.Age);

즉시 두 개의 다른 함수 ( 및 )를 사용 하여 패턴을 나타내는 동일한 코드 (사용 )를 어떻게 활용할 수 있었는지 알 수 있습니다 .Selectp => p.Namep => p.Age

대안은 Select다른 종류의 값에 대해 시퀀스를 스캔하려고 할 때마다 다른 버전을 작성하는 것입니다. 따라서 위와 동일한 효과를 얻으려면 다음이 필요합니다.

// Presumably, the code inside these two methods would look almost identical;
// the only difference would be the part that actually selects a value
// based on a Person.
var names = GetPersonNames(people);
var ages = GetPersonAges(people);

대리자가 자리 표시 자 역할을하므로 이와 같은 경우 동일한 패턴을 반복해서 작성하지 않아도됩니다.


66

Func<T1, T2, ..., Tn, Tr> (T1, T2, ..., Tn) 인수를 취하고 Tr을 반환하는 함수를 나타냅니다.

예를 들어 함수가있는 경우 :

double sqr(double x) { return x * x; }

일종의 함수 변수로 저장할 수 있습니다.

Func<double, double> f1 = sqr;
Func<double, double> f2 = x => x * x;

그런 다음 sqr을 사용하는 것과 똑같이 사용하십시오.

f1(2);
Console.WriteLine(f2(f1(4)));

기타

그러나 더 자세한 정보는 문서를 참조하십시오.


1
하지만 키워드 정적을 compilling에 대한 Excelent 대답은 neeed됩니다
boctulus

16

내가 찾을 Func<T>내가 필요 "즉석에서"맞춤 수있는 구성 요소를 만들 때 매우 유용합니다.

이 아주 간단한 예를 들어 보자 : PrintListToConsole<T>컴포넌트.

이 개체 목록을 콘솔에 인쇄하는 매우 간단한 개체입니다. 이를 사용하는 개발자가 출력을 개인화하도록하고 싶습니다.

예를 들어 특정 유형의 숫자 ​​형식 등을 정의 할 수 있습니다.

Func없이

먼저 입력을 받아 콘솔에 인쇄 할 문자열을 생성하는 클래스 용 인터페이스를 만들어야합니다.

interface PrintListConsoleRender<T> {
  String Render(T input);
}

그런 다음 PrintListToConsole<T>이전에 만든 인터페이스를 가져 와서 목록의 각 요소에 사용 하는 클래스를 만들어야 합니다.

class PrintListToConsole<T> {

    private PrintListConsoleRender<T> _renderer;

    public void SetRenderer(PrintListConsoleRender<T> r) {
        // this is the point where I can personalize the render mechanism
        _renderer = r;
    }

    public void PrintToConsole(List<T> list) {
        foreach (var item in list) {
            Console.Write(_renderer.Render(item));
        }
    }   
}

구성 요소를 사용해야하는 개발자는 다음을 수행해야합니다.

  1. 인터페이스 구현

  2. 실제 수업을 PrintListToConsole

    class MyRenderer : PrintListConsoleRender<int> {
        public String Render(int input) {
            return "Number: " + input;
        }
    }
    
    class Program {
        static void Main(string[] args) {
            var list = new List<int> { 1, 2, 3 };
            var printer = new PrintListToConsole<int>();
            printer.SetRenderer(new MyRenderer());
            printer.PrintToConsole(list);
            string result = Console.ReadLine();   
        }   
    }

Func를 사용하면 훨씬 간단합니다.

컴포넌트 내부에서 T 유형의 입력 매개 변수를 취하고 문자열 (콘솔의 출력)을 리턴하는 함수의 인터페이스Func<T,String>나타내는 유형의 매개 변수를 정의합니다.

class PrintListToConsole<T> {

    private Func<T, String> _renderFunc;

    public void SetRenderFunc(Func<T, String> r) {
        // this is the point where I can set the render mechanism
        _renderFunc = r;
    }

    public void Print(List<T> list) {
        foreach (var item in list) {
            Console.Write(_renderFunc(item));
        }
    }
}

개발자가 구성 요소를 사용할 때 단순히 Func<T, String>유형 의 구현 , 즉 콘솔에 대한 출력을 생성하는 함수를 구성 요소에 전달합니다 .

class Program {
    static void Main(string[] args) {
        var list = new List<int> { 1, 2, 3 }; // should be a list as the method signature expects
        var printer = new PrintListToConsole<int>();
        printer.SetRenderFunc((o) => "Number:" + o);
        printer.Print(list); 
        string result = Console.ReadLine();
    }
}

Func<T>즉석에서 일반 메소드 인터페이스를 정의 할 수 있습니다. 입력 유형과 출력 유형을 정의합니다. 간단하고 간결합니다.


2
이 Marco를 게시 해 주셔서 감사합니다. 정말 도움이되었습니다. 나는 한동안 func를 이해하려고 노력해 왔으며 또한 프로그래밍에서 적극적으로 사용했습니다. 이 예는 경로를 지 웁니다. 나는 그것을 표시하지 못하게하는 원래 코드에서 생략 된 StampaFunc 메서드를 추가해야했다.
Siwoku Adeola

1
Func 샘플에서 누락 된 줄이 있다고 생각합니다. 인쇄 함수 또는 StampaFunc에 대한 호출은 어디에 있습니까?
Bashar Abu Shamaa

11

Func<T1,R>다른 미리 정의 된 제네릭 Func대표 ( Func<T1,T2,R>, Func<T1,T2,T3,R>등)은 최종 제네릭 매개 변수의 형식을 반환 일반적인 대표입니다.

매개 변수에 따라 다른 형식을 반환해야하는 함수가있는 경우 Func반환 형식을 지정 하는 대리자를 사용할 수 있습니다 .


7

미리 정의 된 일반 대리자 일뿐입니다. 그것을 사용하면 모든 델리게이트를 선언 할 필요가 없습니다. Action<T, T2...>동일하지만 void를 반환하는 또 다른 미리 정의 된 대리자가 있습니다 .


0

정보를 추가하기에 너무 늦지 않았을 수도 있습니다.

합집합:

Func는 시스템 네임 스페이스에 정의 된 사용자 지정 대리자로서 0 ~ 16 개의 입력 매개 변수를 사용하고 무언가를 반환해야하는 동일한 서명 (대리자처럼)을 가진 메서드를 가리킬 수 있습니다.

명명법 및 사용 방법 :

Func<input_1, input_2, ..., input1_6, output> funcDelegate = someMethod;

정의:

public delegate TResult Func<in T, out TResult>(T arg);

사용 장소 :

람다 식 및 익명 메서드에 사용됩니다.

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