ProgramingTip

수동으로 델리게이트 만들기 vs Action / Func 델리게이트 사용

bestdevel 2020. 11. 13. 23:50
반응형

수동으로 델리게이트 만들기 vs Action / Func 델리게이트 사용


오늘 나는 선언하는 것에 대해 생각하고 있었다.

private delegate double ChangeListAction(string param1, int number);

그러나 사용하지 않는 이유 :

private Func<string, int, double> ChangeListAction;

또는 ChangeListAction반환 값이 다음을 사용할 수 있습니다.

private Action<string,int> ChangeListAction;

선언 delegate키워드 로 대리 선언 할 때 장점은 무엇입니까?

.NET 1.1 때문 입니까? .NET 2.0 Action<T>과 함께 .NET 3.5와 함께 왔 Func<T>입니까?


장점은 명확합니다. 유형에 명시적인 이름을 지정하면 해당 유형이 수행하는 작업이 더 명확 해집니다.

코드를 때도 도움이됩니다. 다음과 같은 오류 :

cannot convert from Func<string, int, double> to Func<string, int, int, double>

다음과 같이 말하는 것보다 덜 도움이됩니다.

cannot convert from CreateListAction to UpdateListAction

또한 두 가지 작업을 수행하는 경우 컴파일러가 실수로 다른 대리를 수행하는 경우에는 사용하지 않도록 보장 할 수 있습니다.


대리자 사용 의 출현 ActionFunc가족은 사용자 지정 대리 유효성 덜 사용하게 만들었지 만 후자는 여전히을 찾습니다. 사용자 지정 대리자의 장점은 다음과 같다.

  1. 다른 사람들이 지적했음을 일반 Action는 달리 의도를 명확하게 전달합니다 Func( Patrik 은 의미있는 매개 변수 이름에 대해 매우 좋은 지적을합니다).

  2. 다른 두 개의 일반 대리자와 달리 ref/ out매개 변수 를 사용할 수 있습니다 . 예를 들어, 당신은 수 있습니다.

    public delegate double ChangeListAction(out string p1, ref int p2);
    

    하지만

    Func<out string, ref int, double> ChangeListAction;
    
  3. 또한 사용자 지정 델리게이트를 사용하면 ChangeListAction코드베이스 어딘가에 한 번만 작성하면 (정의를 의미합니다). 반면에 정의하지 않는 Func<string, int, double>모든 곳에 흩어져 있어야합니다 . 후자의 경우 서명을 변경하는 것은 번거 롭습니다. 건조하지 않은 나쁜 경우입니다.

  4. 유행하는 매개 변수를 사용합니다.

    public delegate double ChangeListAction(string p1 = "haha", int p2);
    

    하지만

    Func<string, int, double> ChangeListAction = (p1 = "haha", p2) => (double)p2; 
    
  5. params메소드의 매개 변수에 대한 키워드를 누르십시오 Action/Func.

    public delegate double ChangeListAction(int p1, params string[] p2);
    

    하지만

    Func<int, params string[], double> ChangeListAction;
    
  6. 글쎄, 당신이 선호하지 않고 16 개 이상의 변수가 필요하다면 (현재) :)


Action및의 장점 Func:

  1. 빠르고 더러워서 다 사용합니다. 사용 사례가 사소한 경우 코드가 짧아집니다 (사용자 지정 대리자가 나와 함께 유행하지).

  2. 더 중요한 것은 도메인간에 호환되는 유형입니다. Action그리고 프레임 Func워크는 정의, 그들은 한 언어 변수 유형이 일치하게 작동합니다. 당신은 할 수 없습니다 ChangeSomeAction에 대한 ChangeListAction. Linq이 공간을 잘 활용합니다.


대리 선언 적으로 선언하면 일부 유형 검사에 도움이 될 수 있습니다. 컴파일러는 변수에 할당 된 대리자가 서명과 호환되는 임의의 작업이 아닌 ChangeListAction으로 사용할 수 있습니다.

그러나 자신의 대리라는 확실한 가치는 론적 의미를 부여한다는 의미입니다. 코드를 읽는 사람은 델리게이트가 이름으로 무엇을하는지 알 수 있습니다. 세 개의 int 필드가있는 클래스가 대신 세 개의 int 요소의 배열을 선언 할 상상해. 배열은 동일한 작업을 수행 할 수 있습니다. 이름은 개발자에게 유용한 의미 정보를 제공합니다.

LINQ와 같은 범용 라이브러리를 디자인 할 수 있고 Func, Predicate 및 Action 대리 매합니다. 이 경우 대리자는 실행 및 조치를하거나 술어로 사용하고 있고, 게다가 사전 정의 된 의미를 갖지.

참고로 Tuple 대 자체 클래스 자체 클래스 선택 가능합니다. 모든 것을 튜플에 붙일 수있는 속성은 유형 사용에 아무것도 알려주지 않는 항목입니다. Item1, Item2입니다.


일부 답변에서 승리가 명확하게 언급했듯이 유형의 이름을 지정합니다 API 사용자가 이해하기가 더 많았습니다. 대부분의 경우 공개 API에 대한 대리자 유형을 선언하지만 Func<?,?>내부적으로 사용하는 것은 괜찮습니다 .

다른 답변에서 언급되지 않은 대리자 유형을 선언하는 큰 이점 중 하나는 유형에 이름을 지정하는 것 외에 유용성이 크게 증가하는 것입니다.


대표 만 사용할 수있는 특별한 사용 사례를 찾았습니다.

public delegate bool WndEnumProc(IntPtr hwnd, IntPtr lParam);
[DllImport("User32.dll")]
public static extern bool EnumWindows(WndEnumProc lpEnumFunc, IntPtr lParam);

기능 / 동작 사용은 작동하지 않습니다. 'Namespace.Class.WndEnumProc' is a 'field' but is used like a 'type':

public Func<IntPtr, IntPtr, bool> WndEnumProc;
[DllImport("User32.dll")]
public static extern bool EnumWindows(WndEnumProc lpEnumFunc, IntPtr lParam);

다음 코드는 예외가 발생하는 System.Runtime.InteropServices.DllImportAttribute유형의 마샬링을 지원하지 않습니다 .

[DllImport("User32.dll")]
public static extern bool EnumWindows(Func<IntPtr, IntPtr, bool> lpEnumFunc, IntPtr lParam);

나는 모든 사람에게 보여 주기이 예를 제시한다. 그리고 귀하의 질문에 대한 응답입니다why not use Action<T>/Func<T> ?


Func / Action에서 너무 많은 변수를 가져 오기 시작하면 대리 튼 명시 적으로 선언하십시오. "두 번째 정수가 다시 무엇을 의미하는지 의미합니까?"계속해서 무엇을보아야합니다.


더 좋고 더 자세한 답변은 @nawfal을 참조하십시오. 나는 더 단순하게 노력할 것입니다.

클래스의 멤버를 선언하므로 델리게이트를 고수해야합니다. 사용 delegate은 더 설명적이고 구조적입니다.

Action/Func 유형은 전달을 위해 만들어 지므로 매개 변수 및 지역 변수로 더 많이 사용해야합니다.

그리고 실제로 둘 다 상속 Delegate클래스입니다. Action 및 Func는 제네릭 형식이며 다른 매개 변수 형식을 사용하여 대리자를 간단하게 만듭니다. 그리고 delegate 키워드는 실제로 하나의 선언에서 Delegate로부터 상속받은 완전히 새로운 클래스를 생성합니다.


으로 MSDN을 했다, Func<>그 자체가 미리 정의입니다 Delegate. 처음으로 나는 이것에 대해 혼란스러워했습니다. 실험이 끝난 후 이해가 더 명확 해졌습니다. 일반적으로 C #에서는

Type에 대한 포인터로 Instance.

동일한 개념이 적용됩니다.

Delegate 에 대한 포인터로 Method

이것들과 사물의 차이점은 Delegate예를 들어 OOP의 개념을 가지고 있지 않다는 것입니다 Inheritance. 이 일을 더 명확하게하기 위해 저는

public delegate string CustomDelegate(string a);

// Func<> is a delegate itself, BUILD-IN delegate
//==========
// Short Version Anonymous Function
//----------
Func<string, string> fShort = delegate(string a)
{
  return "ttt";
};
// Long Version Anonymous Function
//----------
Func<string, string> fLong = a => "ttt";

MyDelegate customDlg;
Func<string, string> fAssign;
// if we do the thing like this we get the compilation error!!
// because fAssign is not the same KIND as customDlg
//fAssign = customDlg;

프레임 워크의 많은 기본 제공 메서드 (예 : LINQ)는 Func<>delegate 의 매개 변수를받습니다 . 이 방법으로 할 수있는 것은

DeclareFunc<>형식 의 대리자를 Define사용자 지정 대리자가 아닌 함수에 전달합니다 .

예를 들어 위의 코드에서 더 많은 코드를 추가합니다.

string[] strList = { "abc", "abcd", "abcdef" };
strList.Select(fAssign); // is valid
//strList.Select(customDlg); // Compilation Error!!

참고 URL : https://stackoverflow.com/questions/4482613/creating-delegates-manually-vs-using-action-func-delegates

반응형