ExpressionTree JSON 파서 ExpressionTree은 JSON 파서를 달성 달성

JSON 파서를 달성 ExpressionTree

  예년과는 달리, 모든 사람을위한 올해의 봄 축제는 잊지 못할 것입니다. 아니 회사가 사업에 지출하고, 지금 우리 앞에 그러한 삶가 아닌 실제,뿐만 아니라 수 있습니다, 잠을 먹고 수면과 식사 : 그는 우리가 삶을의 "꿈"살아 그래서 코로나 바이러스의 새로운 유형으로 파산 사람들이 편안하게 느낄 수 있도록 학습을 중지합니다. 내가 달성하기 위해 ExpressionTree의 주요 사용이 부분에 물체의 조금, 직렬화 / 역 직렬화를 달성하기 위해 JSON 파서 년 전에 얻을하고 프로젝트를 소개하는이 기사를 쓴 그래서 ( 소스 코드 참조 ).

먼저 사용하는 방법을 보여줍니다 :

  학생

JSON은 학생으로 직렬화 :

var에 JSON = "{\"ID \ "100 \"이름 \ "\"张三 \ ", \"섹스 \ "1 \"생일 \ "\"2000년 10월 10일 \ "} ";
VAR 학생 = JsonParse.To <학생> (JSON);  

학생 JSON으로 직렬화 :

코드를 복사
 학생 = 새로운 학생이었다
            {
                식 (111)
                이름 = "TESTNAME"
                섹스 = Sex.Unkown,
                주소 = "북경시 해정 구"
                생일 = DateTime.Now
            };
            VAR JSON = JsonParse.ToJson (학생);
            // { "ID": 111, "이름": "TESTNAME", "섹스": "알 수없는", "생일": "2020년 2월 15일 17시 43분 31초", "주소": "北京市 海淀区 "}
            VAR 옵션은 새로운 JsonOption을 =
            {
                WriteEnumValue = 사실은, // 열거 값은 직렬화
                DateTimeFormat = "YYYY-MM-DD"// 지정된 형식의 날짜
            };
            VAR json2 = JsonParse.ToJson (학생, 옵션);
            // { "ID": 111, "이름": "TESTNAME", "섹스": 0, "생일": "2020년 2월 15일", "주소": "北京市 海淀 区"}
코드를 복사

직렬화 된 JSON의 목록을 IEnumerable, 배열 :

  var에 JSON = "[{\"ID \ "100 \"이름 \ "\"张三 \ ", \"섹스 \ "1 \"생일 \ "\"2000년 10월 10일 \ " }, {\ "ID \"101 \ "이름 \"\ "李四 \", \ "섹스 \"\ "여성 \", \ "생일 \"널 (null), \ "주소 \" \ "\"}] ";
  var에 목록 = JsonParse.To <목록 <학생 >> (JSON);
  VAR의리스트 2 = JsonParse.To <를 IEnumerable <학생 >> JSON ();
  VAR 도착 = JsonParse.To <학생 []> JSON ();        

목록 <Stuednt> 변환 JSON

코드를 복사
var에 목록 = 새로운 목록 <학생>
            {
                새로운 학생 {식 (123), 이름 = "사용자 이름 1", 성별 = Sex.Male, 생일 = 새로운 날짜 시간 (1980,1,1)},
                새로운 학생 {식 (125), 이름 = "사용자 이름 2", 성별 = Sex.Female}
            };
            VAR json1 = JsonParse.ToJson (목록, TRUE); // 들여 쓰기 형식, 기본 압축 JSON
            / *
            [
                {
                    "ID": 123,
                    "이름": "사용자 이름 1"
                    "섹스": "남성"
                    "생일": "1980년 1월 1일 00:00:00"
                    "주소"널 (null)
                },
                {
                    "ID": 125,
                    "이름": "USERNAME2"
                    "섹스": "여성"
                    "생일"널 (null),
                    "주소"널 (null)
                }
            ] 
            * /
            VAR 옵션은 새로운 JsonOption을 =
            {
                들여 쓰기 = TRUE, // 들여 쓰기
                DateTimeFormat = "YYYY-MM-DD"
                IgnoreNullValue는 널 (null) 출력을 무시 // 진정한 =
            };
            VAR json2 = JsonParse.ToJson (목록, 옵션);
            / *
               [
                    {
                        "ID": 123,
                        "이름": "사용자 이름 1"
                        "섹스": "남성"
                        "생일": "1980년 1월 1일"
                    },
                    {
                        "ID": 125,
                        "이름": "USERNAME2"
                        "섹스": "여성"
                    }
                ]
             * /
코드를 복사

Dictironary에 JSON :

사전에 // JSON
var에 JSON은 = "{\" ": 66,580, \"의심되는 경우 \ "8969 \"치료의 경우 \ "8286 \"죽음 \ "1천5백24가지 경우를 \ 확인}";
VAR DIC = JsonParse.To <사전 <문자열 INT >> JSON ();
VAR dic2 = JsonParse.To <IDictionary <문자열 INT >> JSON ();

 JsonParse이 초점이 소개 가지 않을 것이다 아니라, 내부가 실제로 또한 달성하기 위해 JsonSerializer를 사용할 필요가 더 복잡한 기능을 완료 JsonSerializer를 호출하고, 일부는 정적 메소드의 객체 직렬화 / 역 직렬화를 대체 할 수 있습니다.

  JSON이 포함 두 가지 주요 기능을 분석하는 경우 : 직렬화 및 직렬화 된 객체를 직렬화 복원 문자열 JSON 직렬화 된 JSON 문자열이 지정된 객체로 변환됩니다 변환하는 것입니다. 여러 코어가 IConverterCreator 등 JsonReader, JsonWriter, ITypeConverter이 프로젝트에있는 관련 개체 아래 하나 하나 소개했다.

1 JsonReader JSON 리더

  JsonReader 단순히 주사 JSON 구문 규칙에 따라, 스캐너 JSON 스트링으로서 이해 될 수있다하는 JsonTokenType 아웃 각 스위프 그 값을 대응 JsonTokenType 열거 정의

  코드보기

문자열 검색 방법 읽기 () :

  코드보기

  읽기 방법에서 알 수있는 바와 같이, READSTATE JsonReader 내부 상태 기계를 유지하는 각각의 호출은 READSTATE에 다음의 토큰에 따라 해결 될 정도로, 모두 내부 브랜치 점프의 구동 방법이 쉽게 정정 포맷 JSON 반면 예를 들어 테스트 : 충족  { (StartObject) (공백 문자를 제외한) 다음 유효한 문자 만이  " (PROPERTYNAME) 또는  } (EndObject) 하나의 READSTATE = StartObject ReadProperty () 메소드를 수행하기 위해 이동해야하고,의를 ReadProperty 만 필요 () 메소드   }  ReadProperty () 핵심 코드의 방법으로 다음과되도록 다른 문자가 JSON 파일 형식이 정확하지 않은 설명이 있습니다, 올바른 응답을 할 두 문자는 라인에 예외를 발생 :

  코드보기

.... 점프와 체크 형식과 마찬가지로 치료 방법의 다른 방법과 유사하다.

  토큰 검증 중첩 용기 (된 JSONObject 및 JsonArray)는 즉, 정확한 심볼 이후 폐쇄 여기서 더 번잡 {} , [] [{}} 상기 에러 JSON : 쌍에서 발생한다, 예를 들어 단지 다음의 토큰이 합법적인지 확인하기 위해 토큰을 사용하는 경우 문자열이 합법적되지 않습니다 JSON을 확인할 수 없습니다, 다음 LIFO 스택 기능은이 시나리오에 매우 적합하며, 우리는 스택을 확인하는 데 도움 JSON : 처음 조우 [수행 푸시 동작 {제 푸시 계속} 현재의 값이 닫혀 있는지 셋째, 스택의 값의 풀 동작은 스택의 값을 결정 {,} 제 캐릭터가 합법적와 쌍의 일치로,이 때의 값은 스택 [상단이며, 스택의 값이 [이다} 네 번째 문자 스택 동작} 아닌 쌍, 불법 값, 검증 결말.

  문서를 읽을 정확한 사실 (1) 반품 및 JsonTokenType 완료되지 않은 : JsonReader의 핵심 기능이 해체 및 검증의 JSON 텍스트이며, 핵심 방법 읽기 () 메소드는 3의 존재에있을 것입니다) 읽기 (전화입니다 2. false를 반환, 문서를 읽고 JsonTokenType 모든 것으로 권리 3. 이상, JSON 형식이 올바르지 않거나 구성 요구 사항을 충족하지 않습니다 읽어 보시기 바랍니다. tokentype 매 간의 계층 관계는 다음 ITypeConverter 또는 JSONToken를 포함하여되는 바와 같이 직렬화 상부 JsonReader는 JsonReader JsonTokenType 얻는다 사용 JSON 및 그룹의 대응 값을 판독 한 후, 완료 의존 다른 목적은 처리된다.

2, JosnWriter JSON 작가

  JosnWriter JsonReader 기능과는 반대로, 데이터 JosnWriter 달성 궁극적 사양 JSON JSON 문자열 직렬화 함수 클래스에 따라 출력된다. JsonWriter은 물론, JsonTokenType 값을 쓰는 모든 메소드 호출을 작성, 그들은 또한 체크 값이 합법적 작성해야, 체크 로직을 확인하고 JsonReader 유사한 기능은 상대적으로 간단하고, 관심있는 학생들을 소개하지 않습니다 직접 문서의 끝 부분에 코드에서 코드 주소를 볼 수있다.

3 (트랜스) 직렬 인터페이스 ITypeConverter

 메인 클래스 다이어그램 간의 참조 :

  

  (안티 ITypeConverter 인터페이스는 JsonWriter는, 객체 (드) 직렬화의 특정 유형을 달성하기 위해 전체 객체 직렬화 / 핵심 직렬화 과정, ITypeConverter가 JsonReader에 의존 책임이지만 특정 객체이기 때문에 빛이 충분하지 ITypeConverter있다 ) 직렬하는 ITypeConverter 구현 클래스는 하나 또는 객체의 클래스를 해결할 수, 객체는 ITypeConverter이 작업을 넘겨 어떤 어떤 사용할 때 모르는 외부 호출자, ITypeConverter의 숫자를 해결하는 데 사용됩니다 IConverterCreator의 정의에서 완벽한 모습을 IConverterCreator 공장 :

  코드보기

특정 유형의 지원을 결정하기 위해 ITypeConverter CanConvert 방법 전에 호출 할 필요를 만들려면이 기능을 사용하면, 진정한 반환 할 때 해당 TypeConverter를 만들거나 다른 밖으로 만들어 갈 수 또한 IConverterCreator 후보의 무리를 할 필요가 없습니다 작업, 그렇게 발신자를 찾아, 다음이 후보가 후보에 통과하는 진정한 CanConvert 메서드가 반환 전화를 통과하려면 ITypeConverter이 TypeConverterProvider이 추상 클래스를 기반으로 작업을 시작 만들 수 있습니다 :

  코드보기

이용 IConverterCreator 사용자 정의 구현을 확장 할 수 있으려면, 메소드 AddConverterFactory 외부에서 사용자 정의 IConverterCreator을 추가 할 수 있습니다 제공한다. 기본 방법은 빌드 이송 AllConverterFactories을 달성하고 ITypeConverter을 만들지 여부를 결정하는 것입니다, 그들은 ITypeConverter IConverterCreator 수익을 생성하기 위해 Create 메서드를 호출하는 조건을 충족, 폐쇄를 달성하기 위해 전체 공장 빌더, 이론, 한 IConverterCreator에 충분히 강한만큼 내부 AllConverterFactories로, 그것은 유형의 모든 종류를 변환 할 수 있습니다,이 공장 빌더는 IConverterCreator이 (반) 직렬화 작업의 종류를 달성하기 위해 ITypeConverter을 만들 수 있습니다.

4 ITypeConverter 몇몇 구현과 ExpressionTree  

 4.1 TypeConverterBase

  식 트리 생성기 기능 위임의 사용은 위임 다음 캐시, 및 코드 실행 성능은 상당히 정적 쓸 수 있습니다. 공용 속성 Func을 <object> 때 CreateInstance를 추출 TypeConverterBase, 목적은 직렬화 객체가 식 트리를 사용하여 컴파일 된 수수료를 요구하는 타입을 만드는 것입니다 :

  코드보기

이 방법은 제 생성자 지각 영역 인수가 필요한 경우 유형 생성자 인수가없는, 구조체에 Expression.New (타입)를 통해 직접이 경우 구조물에 적어도 생성자 파라미터를 발견하지 아닌지 확인하지 이러한 매개 변수는 전달되는 기본 구현은 물론 직접 구성 파라미터 데이터의 값 등에 의해 지정 될 수 있으며, 상기 파라미터 타입의 현재의 디폴트 값을 전송한다. 유형이 int이며 유형이 문자열 인 경우, 기본 (INT)에 해당, 기본값으로 해당 (문자열), 등으로하는 경우, 디폴트 값 식 Expression.Default (유형)의 유형을 가져옵니다. 이어서 일정한 발현 Expression.Constant (DEFAULTVALUE)는 식을 변환 목록 <식>에서 다음 생성자 과부하 식 newExp = Expression.New (생성자 parametExps)를 이용하여, 변환에 부가 된 결과를 변환되고 lambad 표현 Expression.Lambda <Func을 <object >> (newExp)는, 당신은 컴파일 방법은 의뢰 생성하기 위해 호출 할 수 있습니다.

  Func을 <object> 때 CreateInstance이 위임 방법으로 만 실행 라인에 의뢰 할 객체의 필요성을 인스턴스화, 당신은 반사의 객체를 만들 필요가 없습니다.

  JsonArray 파서 유형을 처리하는 ObjectConverter, DictionaryConverter : 구현 클래스는 일반적으로 세 가지 종류로 분류된다 TypeConverterBase 입력 파서 된 JSONObject 처리 EnumberableConverter (구체적인 실현 ListConverter, ArrayConverter ...) JSON 프로세스 치형 (JsonString, JsonNumber을 , JsonBoolean, JsonNull) 파서 : ValueConverter. 각 리졸버 타입 JSON (DE) 연재의 각 특성에 대해 수행된다.

 4.2 객체 파서 ObjectConverter

  Func을 <object, object> GetValue 설정 속성 / 필드 값 액션 <object, object> SetValue는 : 오브젝트 속성 / 필드를 확인하고 된 JSONObject 속성 상호 행할 수 위해, 우리는 두 가지 대표 속성을 정의한다. 파라미터는 오브젝트 타입을 사용하여 정의되고, 목적은 상기 방법의 다양성을 보장하는 것이다. GetValue 오브젝트는 속성 / 필드 상당의 반환 값이고, 제 1 기준 객체는 객체 클래스의 현재 인스턴스의 속성 GET / 방법 대리자 필드 값이다. 을 getValue보기는 생성 된 코드를 의뢰 :

  코드보기

실제 필요성을 사용할 때 먼저, 양호한 프로세스 파라미터의 VAR instanceExp = Expression.Parameter (대해서 typeof (오브젝트), "예"), 기준이 Object 형식의 정의는 Expression.Convert (instanceExp, MemberInfo가을 이용하여 그 타입으로 변환 할 .DeclaringType) Expression.Convert 수행은 instanceTypeExp 형식 변환 (Expression.TypeAs 또한 변환을 입력 할 수 있지만, 입력 할 경우 변환이 불평 값 형식에만 참조 형식을 변환하는 데 사용될 수있다), 그 다음 Expression.PropertyOrField를 사용 (인 MemberInfo.Name)는 멤버 인스턴스의 이름을 전달하고, 부재의 값을 얻을 수있는 것은,이 로직은 다음의 의사 코드의 방법을 getValue 동등하다 :

1
4
5
6
protected  object  GetValue( object  obj)
         {
             var  instance = (目标类型)obj;
             var  value = instance.目标属性/字段;
             return  ( object )value;
         }

SetValue를 생성 로직 봐 의뢰 :

  코드보기

할당이 반환 값을 가질 필요는없고, 최초의 파라미터는 상기 객체의 인스턴스이며, 두 번째 파라미터는 상기 객체의 부재이다 Expression.Parameter 방법 선언 통해 Expression.PropertyOrField 정적 코드의 인스턴스 발현 속성 / 필드 대응을 얻는 것이다. 이러한 표현 속성 / 필드 이름, 회원 대입 표현식 : Expression.Assign (memberExp, Expression.Convert (이 된 ValueExp, MemberType)), 인삼 문의 멤버 객체, 변환에 Expression.Convert (이 된 ValueExp, MemberType)를 호출하기 위해 동일한 필요 진정한 타입으로. 그런 다음 의뢰 목표를 생성 할 수 있습니다 Expression.Lambda 컴파일 방법을 사용합니다.

  클래스는 어디에 여러 속성 / 필드, 자신의 요구 GetValue / SetValue를에 해당하는 각 속성 / 필드가있을 것입니다, 우리는 (A MemberDefinition 만 회원 정보를 관리, GetValue / SetValue를 배치 MemberDefinition 클래스를 통합 의뢰 한 생성합니다 여러 속성 / 필드를 매핑하는 MemberDefinition 공공는 IEnumerable <MemberDefinition> MemberDefinitions 현재 클래스의 목록을 유지 PropertyInfo 또는의 fieldInfo) 읽고 ObjectConverter에서 다음 쓰기 의뢰 세대는, 각 구성원 또는 값을 쓰기에 할당 바로 찾을 필요 해당 MemberDefinition는 다음의 GetValue / SetValue는 그것을 의뢰 호출합니다.

 4.3 사전 형 파서 DictionaryConverter

두 개의 특성을 유지하기 위해 필요한 키 값의 형태로 사전 DictionaryConverter <>와 일반 인터페이스로 된 JSONObject 간의 상호 변환을 처리 할

1
public  Type KeyType {  get protected  set ; }
 
public  Type ValueType {  get protected  set ; }

 할당 / 쓰기 값의 형식을 변환 할 때 두 종류의 속성 유형은 사용할 수 있습니다. 방법 및 객체 멤버가 동일한 할당 아니며, 키 인덱스, 대리인 할당 사전에 의해 달성 될 수있는 사전 읽어 액션 <object는, 오브젝트가 오브젝트> 첫 번째 파라미터가 사전 예이다, 두 번째 인수는 키는 DIC [키 = 값; 모습이 표현 코드 생성을 위임 : 값은 상기 제 3 값이 통화를 수행하는 코드를 위임 동일한 파라미터의 값이다 :

  코드보기

새로운 type.GetProperty ( "항목": 대리자 객체 파라미터들의 세 가지 유형으로 더 리턴 값 Expression.Parameter가 정의되지 않았습니다 각각 다음 각 실제 데이터 형식으로 변환 한 다음 인덱스가 대응 반사기 PropertyInfo를 찾는 타입 []는 {에 KeyType}) (지수 특성 인덱서 Expression.MakeIndex주고) 항목 디폴트 이름 (dicExp은 [{keyExp})에 대응하는 값으로 키 구문을 판독 속성, 새로운 표현 인덱스이며 할당은, 당신은 또한 인덱스를 얻기 위해위원회가 할당되어 있으므로, 완료 Expression.Assign (indexExp, ValueExp를 취득)를 사용해야합니다. 사전 키 값 인수 값이 위임 : Func을 <개체, 개체, 개체>와 논리적 할당은 기본적으로 동일, 단지 인덱서 반환에게 빈의 결과를 얻을 수, 코드가 게시되지 않습니다.

4.4 반복적 유형일 수있다 (는 IEnumerable 인터페이스 구현 형) 리졸버 EnumerableConverter

   인터페이스 및 대리자 두 함수의 유형을 IEnumerable JsonArray 주 사용 간의 전환을 달성한다 Func을 <object, IEnumerator를> GetEnumerator를하고 액션 <object는 object> 읽기 및 쓰기에 각각 대응 AddItem을는, 판독 얻을 IEnumerable을 인 반복자하는 GetEnumerator (), 다음 반복자를 통과, 쓰기 컬렉션에 요소를 추가하고, 궁극적으로 그 자체가 추가라는 이름을 추가 할 수있는 모든 데이터 수집 방법부터 방법을 "추가"를 호출 모음입니다, EnumerableConverter는 추상 클래스하므로, 단지 전체에 특정 구현 클래스에 의해 구현 공통의 로직 부분을 달성 (예 : ListConverter, ArrayConverter ...). 생성 된 코드를 설정 반복자 위임 대리인 생성 된 코드 데이터를 취득하여 첨가 붙여

  BuildGetEnumberatorMethod
  BuildAddItemMethod

   그냥 사용 EnumerableConverter이 객체 GetEnumerator를 대리자를 직렬화 할 때, 반복자에게있는 IEnumerator를 얻을, 전화 반복자는 그것을 JSON으로 각 항목의 출력을 통과합니다. AddItem을 대리자 직렬화 오브젝트 데이터의 수집을 완전히 채우는 데이터를 추가하고 그 메소드를 호출 수행과 동일하게 설정. 그러나 배열을 처리하는 방법의 요소를 추가 할 방법이없는, 불변? 여기서 접근리스트에 의해 달성 제의 어레이를 구성하는 경우에있어서 대상 배열로 변환한다 () ToArray의 단부 통합 통화 목록에서에는 list.add 방법을 사용하여 데이터를 추가 할 수있다. ArrayConverter가 ListConverter에서 상속, 부모 클래스 ListConverter의 직렬화 방법을 다시 그래서, 완료 처리 된 부모 클래스의 목록 ToArray 메서드를 호출합니다.

  소개되지 않은 여기에 특정 구현 많이 있습니다, 주로 식 트리가 연구 노트, 부수적 공유로 기록 된이 물건을 알고 있습니다.

  많은 문제가 있어야합니다, 디자인 아이디어 Newtonsoft.Json 참조 소스, 내 수준에 따라 플러스 프로젝트의 일부가 완전히 테스트되지 않은 한, 배우고 분석 식 트리를 JSON 사용하는 주로이 프로젝트를 쓰기 나 우리가 함께 배우고 발전하는 희망으로, 제시 거물 수정에 오신 것을 환영합니다. 마지막으로, 나는 이동 벽돌로 일찍 돌아가, 전염병에 대한 조기 종료를 희망한다.

  소스 주소를 붙여 넣습니다 https://github.com/zhangmingjian/RapidityJson

추천

출처www.cnblogs.com/Leo_wl/p/12518993.html