2013-05-19 4 views
0

나는 내가 Enumerable.Where의 인수로 사용할 수 있습니다 x => x < 5-"lt 5"을 구문 분석, 예를 들어 , C#에서 람다 식으로 문자열을 구문 분석하고 싶습니다 :중첩 된 람다 식을 사전에 저장할 수 있습니까?

static void Main(string[] args) 
{ 
    Enumerable 
     .Range(0,10) 
     .Select(x => (double)x) 
     .Where(Parse("lt 5")) 
     .ToList() 
     .ForEach(System.Console.WriteLine); 
} 

private const List<Tuple<List<string>, Func<double, Func<double, bool>>>> operationList = 
    new Dictionary<string, Func<double, Func<double, bool>>>() 
    { { "lt <",  val => (x => x < val) } 
    , { "le <=", val => (x => x <= val) } 
    , { "eq = ==" , val => (x => x == val) } 
    , { "ne != <>", val => (x => x != val) } 
    , { "ge >=", val => (x => x >= val) } 
    , { "gt >",  val => (x => x > val) } } 
    .Select(kv => 
     new Tuple< 
      List<string>, 
      Func<double, Func<double, bool>>>(
       kv.Key.Split(' ').ToList(), 
       kv.Value)) 
    .ToList(); 

public static Func<double, bool> Parse(string raw) 
{ 
    var fields = raw.Split(' '); 
    var predKey = fields[0].ToLower(); 

    var predBuilder = operationList.FirstOrDefault(tp => 
     tp.Item1.FirstOrDefault(key => key.Equals(predKey)) != null); 

    return predBuilder.Item2(double.Parse(fields[1])); 
} 

먼저 나는 operationList 저장했다 튜플. Item1은 연산자에 대한 모든 별칭을 설명하고 Item2은 연산자의 카레 버전을 저장합니다.

Parse은 문자열 lt 5["lt","5"]으로 분할하고 키 lt에 따라 작업을 검색합니다.

마지막으로 연산을 찾을 수 있다면 5이 부분 적용되고 결과는 람다 식 x => x < val이됩니다.

그러나 컴파일러는 { "lt <", val => (x => x < val) }에 화를 냈고 "표현식에 익명 메소드 또는 람다 표현식을 포함 할 수 없습니다."라는 불평을했습니다.

나는 그것이 무엇을 의미하고 어떻게 작동하는지 알지 못합니다.

답변

1

변경과 같이 readonly-const하고 그것을 static을은 : C#에서

private readonly static List<Tuple<List<string>, Func<double, Func<double, bool>>>> operationList = 
    new Dictionary<string, Func<double, Func<double, bool>>>() 
    { { "lt <",  val => (x => x < val) } 
    , { "le <=", val => (x => x <= val) } 
    , { "eq = ==" , val => (x => x == val) } 
    , { "ne != <>", val => (x => x != val) } 
    , { "ge >=", val => (x => x >= val) } 
    , { "gt >",  val => (x => x > val) } } 
    .Select(kv => 
     new Tuple< 
      List<string>, 
      Func<double, Func<double, bool>>>(
       kv.Key.Split(' ').ToList(), 
       kv.Value)) 
    .ToList(); 

const 키워드는 시간 상수를 컴파일 나타내는 데 사용되지만, 귀하의 예제에서 목록은 LINQ를 사용하여 런타임에 계산됩니다.

C# const에서 값은 항상 정적이며 읽기 전용으로 만들면 필드의 범위가 인스턴스로 변경됩니다.

목록 내용은 실행 중에 변경 될 수 있으며 readonly은 사용자가 목록에서 튜플을 제거하고 추가하는 것을 중단하지 않습니다. ReadOnlyCollection을 사용하는 것이 좋습니다 (수정하지 말고 더 열심히 할 것입니다). 또는 Immutable Collections (.net BCL)의 부분이 아닙니다.

관련 문제