2010-08-01 3 views
4

나는 다른 지점에서 작은 작업을 반복해야하는 메서드를 작업하고 있지만 반복되는 코드는 메서드에 전용이어야합니다. 분명한 해결책은 중첩 된 함수입니다. 그러나 무엇을 시도해도 C# 컴파일러는 나에게 barfs를 사용합니다. 이 펄 스 니펫 (snippet)와 거의 동일한함수를 메서드에 비공개로 만드는 방법은 무엇입니까?

뭔가 :

my $method = sub { 
    $helper_func = sub { code to encapsulate }; 

    # more code 

    &$helper(called whenever needed); 

    # more code 
} 

내가 무슨 말을하고 무엇을, 나는 C#으로 달성하기 위해 노력하고있어 것입니다.

이 컨텍스트에서 클래스의 다른 메서드는 도우미 함수에 액세스 할 수 있어야합니다. C#에서이 구문을 작성하는 가장 논리적 인 방법은 다음과 같습니다.

var helper = (/* parameter names */) => { /* code to encapsulate */ }; 

실제로 컴파일러에서 보관해야합니다. 실제로 나 쓸 수 어떤 CSC 방법 — 내에 델리게이트 타입 선언되어, 람다 대신 이전 대리자() {} 문법을 이용하여 등가이고, 같은 과제는 , 금지되므로

그러나, 이것이다 :

복사 주위 코드의 덩어리를 붙여 손으로 매개 변수를 편집 있지만 유지보다 클래스의 나머지 부분에 개인 대리자 형식을 오히려 누설하지에 대한 모든 벌금과 멋쟁이
private delegate /* return type */ Helper(/* parameters */); 
private /* return type */ method(/* parameters */) { 

    Helper helper = (/* parameter names */) => { 
     /* code to encapsulate */ 
    }; 

    // more code 

    helper(/* called whenever needed */); 

    // more code 
} 

그것은 메서드에 전용입니다. 처음부터 목적을 이겨내지 못했습니다. 매개 변수에 goto 문과 로컬 변수를 사용하면 코드 재사용을 희생하지 않고도이 상황에서 "도우미"를 더 잘 캡슐화 할 수 있습니다. 레지스터를 통해 매개 변수를 전달하여 함수 호출을 시뮬레이트하려면 어셈블러를 사용하는 것이 좋습니다. 문제를 모두 피하기 위해 코드를 리팩터링하는 허용 가능한 방법을 찾지 못했습니다.

그래서 이걸 Common Object Oriented Language에 따르도록 할 수 있습니까?

+1

'Action' 또는 제네릭 버전이란 무엇입니까? –

+0

나는 System.Action과 System.Func에 대해 들어 본 적이 없다는 이유로 사과를해야만하는 것처럼 보입니다. MSDN을 보면, C# 3.5에서 몇 가지 새로운 기능을 놓친 것 같습니다 :-). – TerryP

+0

NET3.5 또는 C# 3.0 (모든 사람을 혼란에 빠뜨릴 수 있음) –

답변

6

C# 3.5 이상인 경우 lambda 및 편리한 위임자 선언 Func<>Action<>을 활용할 수 있습니다.예를

void DoSomething() 
{ 
    Func<int,int> addOne = (ii) => ii +1; 
    var two = addOne(1); 
} 

에 대한 이유는 당신이 하지

var addOne = (ii) => ii +1; 

때문에 Homoiconicity이다 할 수 있도록, 람다는 두 개의 서로 다른 구조, 대리자와 식 트리로 해석 될 수있다. 따라서 선언에서 명시해야 할 필요가있다.

+0

다른 사람들이 검색을 통해 걸려 넘어지기 쉽도록 "3.5 이상"이라고 메모하기 때문에 동료들 사이에서 대답으로 받아들입니다. – TerryP

+0

당신이 옳았지만 엄격하게 말하면 (또는 IL을 볼 때) 그것은 클래스 필드를 선언하고, 델리게이트를 저장하고 그것을 호출하는 멋진 방법입니다. 그래서 일리노이를 볼 때 숨겨지지 않습니다 (이름으로는 가려져 있지만 숨겨져 있지는 않음) –

+0

Btw : C# 2.0에서는 람다 식 대신 익명의 대리자를 사용하는 것이 트릭입니다. –

-1

사실 아주 간단합니다. 메서드가 현재 클래스보다 다른 책임이있는 것 같습니다 (이 메서드를 숨길 이유가 무엇입니까?) 메서드를 자신의 클래스로 옮기고 새 클래스의 개인 메서드에 비공개로 지정할 부분을 옮깁니다.

+0

"이 작은 위임자 문제가 컴파일러에서 발생하므로 디자인을 완전히 변경해야합니다." – zneak

+0

현재 클래스와 아무런 관련이없는 메서드를 자신의 클래스로 옮기는 것은 실제로 좋은 디자인이며 큰 변화가 아닙니다. 접근 방식을 재고하지 않고도 솔루션을 강제 실행하려는 것은 더 나쁜 결정입니다. – dbemerlin

+0

당신은 당신이 아무것도 모르는 방법과 수업에 대해 많은 정보를 추측 할 수 있습니까? 컴파일러 기능에 대한 간단한 질문에 OP 디자인의 타당성에 대해 질문 할 필요가 없다고 생각합니다. – zneak

8

실제로 C#에서이 작업을 수행 할 수 있습니다.

Func<T1, T2, ..., TReturn> myFunc = (a, b, ...) => 
{ 
    //code that return type TReturn 
}; 


대신 Func을 반환 유형 무효 사용 작업의 익명 방법이 필요한 경우 : 당신이 명시 적으로 입력하면

Action<T1, T2, ...> myAction = (a, b, ...) => 
{ 
    //code that doesn't return anything 
}; 
+0

+1 http://en.wikipedia.org/wiki/Closure_(computer_science) –

4

, 그것은 작동, 즉

Action<paramType1, paramType2> helperAction = (/* parameter names */) => { /* code to encapsulate */ }; 
Func<paramType1, paramType2, returnType> helperFunction = (/* parameter names */) => { /* code to encapsulate */ }; 

을 이유가 var 작동하지 않는 이유는 람다식이 여러 유형으로 평가 될 수 있기 때문입니다. (위임 또는 표현식 트리를 믿지만 나에게 인용하지 마십시오.)이 상황에서 컴파일러는 어떤 의미인지 추측 할 수 없습니다.

+0

왜 var가 람다 식에서 실패하지만 이전 Delegate() {} 구문이 컴파일러에서 쉽게 추론해야하는지 그럴듯한 사운드가 있습니다. var x = delegate() {return constantexpr}; 또한 오류입니다. 어쩌면 그것은 "죄송합니다. 아직 C# 6.0에있는 사람들 일 수도 있습니다!" :-에스. – TerryP

1

람다 또는 대리인에 var 키워드를 사용할 수 없습니다. 추가 컨텍스트 정보가 필요하므로 대리자에는 반환 형식이 필요하고 람다에는 반환 형식과 매개 변수 형식이 필요합니다. 예를 들어, (params) => { code } 구문을 사용하려면 매개 변수 유형과 작동 유형을 유추 할 수 있어야합니다. 명시 적으로 유형을 지정하면됩니다. 당신이 무슨 말을 하려는지

일반 System.Action 대리자 형식 (반환 void가)에서 좋은 일을 할 수있는 :

Action<ArgumentType1, ArgumentType2, ...> myDelegate = (params) => { code }; 

그렇지 않으면, 또한 반환 형식이있는 System.Func, 거기에 그 같이 전달해야합니다 마지막 일반 인자.

2

나는 Action<T>Func<TResult> 대표와 자신의 오버로드를보고하는 것이 좋습니다. 당신은 여기 SomeMethod 개인이며 int를 취하고 그것에 무언가를 로컬 Action<int> 위양을 가지고이

static void Main(string[] args) 
{ 
    SomeMethod(); 
} 

private static void SomeMethod() 
{ 
    Action<int> action = (num) => Console.WriteLine(num); 

    Enumerable.Range(1,10).ToList().ForEach(action); 

    Console.ReadKey(); 
} 

과 같은 작업을 수행 할 수 있습니다.

내가 겪은 문제는 λ 식을 변수에 할당 할 때 암시적인 입력 (예 : var 사용)을 사용할 수 없다는 것입니다.

0

숨기기 정의에 따라 다릅니다. 의 IL 당량 볼 때

FUNC/작업 용액 정규 C# 코드를 작성할 때

void DoSomething() 
{ 
    Func<int,int> addOne = (ii) => ii +1; 
    var two = addOne(1); 
} 

Feals hidding 같은 방법 정의 (하나 스콧 등이 제안)되지만

//This is pseudo code but comes close at the important parts 
public class Class1 
    { 
     //The actual type is different from this 
     private static Func<int, int> myMethod = AnonymousFunction; 

     public void f() 
     { 
      myMethod(0); 
     } 

     private static int AnonymousFunction(int i) 
     { 
      return 1; 
     } 
    } 

그래서 당신이 정말로 "hidding"하나의 외부에서 메소드에 접근하고 싶다면 리플렉션으로 이것을 할 수 있습니다. 델리게이트를 저장하는 필드에 대해 생성 된 실제 이름은 CLR 컨텍스트에서 유효한 C# bul에서는 유효하지 않지만 그 것이 유일한 것입니다. 델을 사용하는 길에 서서 필드에 저장된 일반 대리인으로서 egate (이름을 알아내는 경우)

관련 문제