C # 7.0 의 새로운 구현 을보고 있는데 로컬 함수를 구현했다는 것이 흥미 롭지 만 람다 식보다 로컬 함수가 선호되는 시나리오와 두 가지의 차이점은 무엇인지 상상할 수 없습니다.
람다는 anonymous
함수이지만 로컬 함수는 아니지만 함수는 람다 식보다 이점이있는 실제 시나리오를 파악할 수 없습니다.
어떤 예라도 대단히 감사하겠습니다. 감사.
C # 7.0 의 새로운 구현 을보고 있는데 로컬 함수를 구현했다는 것이 흥미 롭지 만 람다 식보다 로컬 함수가 선호되는 시나리오와 두 가지의 차이점은 무엇인지 상상할 수 없습니다.
람다는 anonymous
함수이지만 로컬 함수는 아니지만 함수는 람다 식보다 이점이있는 실제 시나리오를 파악할 수 없습니다.
어떤 예라도 대단히 감사하겠습니다. 감사.
답변:
이것은 C # 디자인 미팅 노트에서 Mads Torgersen이 로컬 기능을 처음 논의한 곳에서 설명했습니다 .
도우미 기능이 필요합니다. 단일 함수 내에서만 사용하고 있으며 포함하는 함수의 범위에 속하는 변수 및 유형 매개 변수를 사용합니다. 반면에 람다와는 달리 람다와는 일등 객체가 필요하지 않으므로 델리게이트 유형을 지정하고 실제 델리게이트 객체를 할당 할 필요가 없습니다. 또한 재귀 적이거나 일반적인 것이거나 반복자로 구현하기를 원할 수 있습니다.
더 확장하면 장점은 다음과 같습니다.
공연.
람다를 만들 때는 델리게이트를 만들어야하는데,이 경우 불필요한 할당입니다. 로컬 함수는 실제로 함수일 뿐이며 델리게이트가 필요하지 않습니다.
또한 로컬 함수는 로컬 변수를 캡처 할 때보다 효율적입니다. 람다는 일반적으로 변수를 클래스로 캡처하는 반면 로컬 함수는을 사용하여 전달되는 struct를 사용하여 ref
할당을 다시 피할 수 있습니다.
또한 로컬 함수 호출이 저렴하고 인라인 될 수 있으므로 성능이 더욱 향상 될 수 있습니다.
로컬 함수는 재귀적일 수 있습니다.
람다는 재귀 적 일 수도 있지만 null
, 대리자 변수에 할당 한 다음 람다에 할당 하는 어색한 코드가 필요합니다 . 로컬 함수는 자연스럽게 재귀적일 수 있습니다 (상호 재귀 적 포함).
로컬 기능은 일반적 일 수 있습니다.
람다는 구체적인 유형의 변수에 할당해야하기 때문에 일반이 될 수 없습니다 (해당 유형은 외부 범위의 일반 변수를 사용할 수 있지만 동일하지는 않습니다).
로컬 함수는 반복자로 구현할 수 있습니다.
Lambdas 는 yield return
(and yield break
) 키워드를 사용하여 IEnumerable<T>
반환 함수 를 구현할 수 없습니다 . 지역 기능이 가능합니다.
로컬 기능이 더 좋아 보입니다.
이것은 위의 인용문에서 언급되지 않았으며 개인적인 편견 일 수도 있지만 일반적인 함수 구문은 람다를 대리자 변수에 할당하는 것보다 낫다고 생각합니다. 지역 기능도 간결합니다.
비교:
int add(int x, int y) => x + y;
Func<int, int, int> add = (x, y) => x + y;
Func<int, int, int> f = (x, y) => x + y; f(arg1:1, arg2:1);
..
svick의 큰 대답 외에도 로컬 함수 에는 또 다른 이점이
있습니다 return
. 명령문 후에도 함수의 어느 곳에서나 정의 할 수 있습니다 .
public double DoMath(double a, double b)
{
var resultA = f(a);
var resultB = f(b);
return resultA + resultB;
double f(double x) => 5 * x + 3;
}
#region Helpers
의 맨 아래에 배치하는 데 익숙해 질 수 있으므로 해당 함수 내에서 혼란을 피하고 주 클래스에서 혼란을 피할 수 있기 때문에 정말 유용합니다 .
로컬 기능을 테스트하는 방법이 궁금하다면 JustMock에 기능이 있는지 확인 해야합니다. 테스트 할 간단한 클래스 예제는 다음과 같습니다.
public class Foo // the class under test
{
public int GetResult()
{
return 100 + GetLocal();
int GetLocal ()
{
return 42;
}
}
}
다음은 테스트 모습입니다.
[TestClass]
public class MockLocalFunctions
{
[TestMethod]
public void BasicUsage()
{
//Arrange
var foo = Mock.Create<Foo>(Behavior.CallOriginal);
Mock.Local.Function.Arrange<int>(foo, "GetResult", "GetLocal").DoNothing();
//Act
var result = foo. GetResult();
//Assert
Assert.AreEqual(100, result);
}
}
다음은 JustMock 설명서에 대한 링크 입니다.
부인 성명. 저는 JustMock을 담당하는 개발자 중 한 사람입니다 .
.DoNothing().OccursOnce();
나중에 Mock.Assert(foo);
메소드 를 호출하여 호출했다고 주장합니다 . 다른 시나리오가 어떻게 지원되는지 관심이 있으시면 Asserting Occurrence 도움말 기사를 읽으십시오 .
더 긴 실행 방법을 다룰 때 가비지 수집 압력을 피하기 위해 인라인 함수를 사용합니다. 주어진 시세 기호에 대해 2 년 또는 시장 데이터를 얻고 싶다고 가정하십시오. 또한 필요한 경우 많은 기능과 비즈니스 로직을 포장 할 수 있습니다.
하나는 서버에 대한 소켓 연결을 열고 이벤트를 이벤트에 바인딩하는 데이터를 반복하는 것입니다. 클래스가 설계된 것과 같은 방식으로 생각할 수 있습니다. 단 하나의 기능에 대해서만 작동하는 헬퍼 메소드를 작성하는 것은 아닙니다. 아래는 이것이 어떻게 보일지에 대한 샘플입니다. 변수를 사용하고 있으며 "helper"메서드가 마지막에 있습니다. 마지막으로 Exchange 클래스가 외부 / 주입 된 경우 이벤트 처리기를 멋지게 제거합니다. 보류중인 이벤트 처리기가 등록되지 않았습니다.
void List<HistoricalData> RequestData(Ticker ticker, TimeSpan timeout)
{
var socket= new Exchange(ticker);
bool done=false;
socket.OnData += _onData;
socket.OnDone += _onDone;
var request= NextRequestNr();
var result = new List<HistoricalData>();
var start= DateTime.Now;
socket.RequestHistoricalData(requestId:request:days:1);
try
{
while(!done)
{ //stop when take to long….
if((DateTime.Now-start)>timeout)
break;
}
return result;
}finally
{
socket.OnData-=_onData;
socket.OnDone-= _onDone;
}
void _OnData(object sender, HistoricalData data)
{
_result.Add(data);
}
void _onDone(object sender, EndEventArgs args)
{
if(args.ReqId==request )
done=true;
}
}
아래에 언급 된 바와 같은 장점을 볼 수 있습니다. 여기서 샘플 구현을 볼 수 있습니다. 이점을 설명하는 데 도움이되기를 바랍니다.