.net Func 변환 .net 표현식으로>
메서드 호출을 사용하면 람다에서 표현식으로 쉽게 이동할 수 있습니다.
public void GimmeExpression(Expression<Func<T>> expression)
{
((MemberExpression)expression.Body).Member.Name; // "DoStuff"
}
public void SomewhereElse()
{
GimmeExpression(() => thing.DoStuff());
}
그러나 펑크를 드문 경우에만 표현으로 바꾸고 싶습니다 ...
public void ContainTheDanger(Func<T> dangerousCall)
{
try
{
dangerousCall();
}
catch (Exception e)
{
// This next line does not work...
Expression<Func<T>> DangerousExpression = dangerousCall;
var nameOfDanger =
((MemberExpression)dangerousCall.Body).Member.Name;
throw new DangerContainer(
"Danger manifested while " + nameOfDanger, e);
}
}
public void SomewhereElse()
{
ContainTheDanger(() => thing.CrossTheStreams());
}
작동하지 않는 줄은 컴파일 타임 오류를 발생시킵니다 Cannot implicitly convert type 'System.Func<T>' to 'System.Linq.Expressions.Expression<System.Func<T>>'
. 명시 적 캐스트는 상황을 해결하지 못합니다. 내가 간과 할 수있는 시설이 있습니까?
아, 전혀 쉽지 않습니다. 식이 아닌 Func<T>
일반을 나타냅니다 delegate
. 컴파일러에서 수행하는 최적화 및 기타 작업으로 인해 수행 할 수있는 방법이 있으면 일부 데이터가 버려 질 수 있으므로 원래 표현식을 다시 가져 오는 것이 불가능할 수 있습니다 .IL을 즉시 분해합니다. 그리고 표현을 추론하는 것은 결코 쉬운 일이 아닙니다. 람다 식을 데이터 ( Expression<Func<T>>
)로 처리하는 것은 컴파일러에서 수행하는 마술입니다 (기본적으로 컴파일러는 코드로 식 트리를 IL로 컴파일하는 대신 코드로 작성합니다).
관련 사실
이것이 람다를 극단으로 밀어주는 언어 (예 : Lisp)가 통역사 로 구현하기 쉬운 이유 입니다. 이러한 언어에서 코드와 데이터는 본질적으로 동일 하지만 ( 런타임 에도 ) 칩은 해당 코드 형식을 이해할 수 없으므로이를 이해하는 인터프리터 (interpreter)를 구축하여 이러한 머신을 에뮬레이트해야합니다. 언어와 같은 Lisp의 선택) 또는 어느 정도 (C #에서 선택한) 힘을 희생 (코드는 더 이상 데이터와 정확히 동일하지 않음)를 희생합니다. C #에서 컴파일러는 컴파일 타임에 람다를 코드 ( Func<T>
) 및 데이터 ( Expression<Func<T>>
) 로 해석 할 수 있도록하여 코드를 데이터로 취급하는 환상을 제공합니다 .
private static Expression<Func<T, bool>> FuncToExpression<T>(Func<T, bool> f)
{
return x => f(x);
}
아마도해야 할 일은 방법을 바꾸는 것입니다. Expression>을 가져 와서 컴파일하고 실행하십시오. 실패하면 이미 식을 살펴보아야합니다.
public void ContainTheDanger(Expression<Func<T>> dangerousCall)
{
try
{
dangerousCall().Compile().Invoke();;
}
catch (Exception e)
{
// This next line does not work...
var nameOfDanger =
((MemberExpression)dangerousCall.Body).Member.Name;
throw new DangerContainer(
"Danger manifested while " + nameOfDanger, e);
}
}
public void SomewhereElse()
{
ContainTheDanger(() => thing.CrossTheStreams());
}
분명히 이것의 성능에 대한 영향을 고려해야하고 그것이 실제로해야 할 일인지 결정해야합니다.
그러나 .Compile () 메소드를 통해 다른 방법으로 갈 수 있습니다-이것이 유용한 지 확실하지 않습니다.
public void ContainTheDanger<T>(Expression<Func<T>> dangerousCall)
{
try
{
var expr = dangerousCall.Compile();
expr.Invoke();
}
catch (Exception e)
{
Expression<Func<T>> DangerousExpression = dangerousCall;
var nameOfDanger = ((MethodCallExpression)dangerousCall.Body).Method.Name;
throw new DangerContainer("Danger manifested while " + nameOfDanger, e);
}
}
public void SomewhereElse()
{
var thing = new Thing();
ContainTheDanger(() => thing.CrossTheStreams());
}
때로는 표현이 필요하고 때로는 대리인이 필요한 경우 두 가지 옵션이 있습니다.
- 다른 방법이 있습니다 (각각 1 개)
- 항상
Expression<...>
버전을 수락하고.Compile().Invoke(...)
대리인을 원할 경우 에만 버전을 수락하십시오 . 분명히 이것은 비용이 든다.
NJection.LambdaConverter 는 대리자를 식으로 변환하는 라이브러리입니다.
public class Program
{
private static void Main(string[] args) {
var lambda = Lambda.TransformMethodTo<Func<string, int>>()
.From(() => Parse)
.ToLambda();
}
public static int Parse(string value) {
return int.Parse(value)
}
}
Expression<Func<T>> ToExpression<T>(Func<T> call)
{
MethodCallExpression methodCall = call.Target == null
? Expression.Call(call.Method)
: Expression.Call(Expression.Constant(call.Target), call.Method);
return Expression.Lambda<Func<T>>(methodCall);
}
Cecil Mono 팀의 JB Evain은이를 가능하게하기 위해 몇 가지 진전을 보이고 있습니다.
http://evain.net/blog/articles/2009/04/22/converting-delegates-to-expression-trees
Change
// This next line does not work...
Expression<Func<T>> DangerousExpression = dangerousCall;
To
// This next line works!
Expression<Func<T>> DangerousExpression = () => dangerousCall();
참고URL : https://stackoverflow.com/questions/767733/converting-a-net-funct-to-a-net-expressionfunct
'Programming' 카테고리의 다른 글
파이썬의 json 모듈, int 사전 키를 문자열로 변환 (0) | 2020.07.27 |
---|---|
std :: vector의 초기 크기를 설정하는 방법은 무엇입니까? (0) | 2020.07.27 |
Eclipse에서 프로젝트를 그룹화 할 수 있습니까? (0) | 2020.07.27 |
문자열 값 앞의 'u'기호는 무엇을 의미합니까? (0) | 2020.07.27 |
size_t의 정의는 어디에 있습니까? (0) | 2020.07.27 |