"Strong Delphi RTTI- 여러 개발 언어를 이해해야 할 필요성에 대한 토론"기사에서 Delphi의 RTTI를 사용하여 데이터 세트의 간단한 객관화를 구현한다고 말했습니다. 이 기사는 내 구현 방법을 자세히 소개합니다.
간단한 예에서 시작하겠습니다. Roswen 데이터베이스에 연결되는 Adodataset 컨트롤이 있다고 가정하고 SQL은 다음과 같습니다.
직원에서 *를 선택하십시오
이제 컨텐츠에 4 개의 필드 직원, FirstName, LastName 및 BirthDate를 ListView에 표시해야합니다. 기존 코드는 다음과 같습니다.
adodataset1이 시작되면 eof가 시작됩니다. FieldByName ( 'lastname').
여기에는 몇 가지 주요 문제가 있습니다.
1. 우선, 매우 장점이 많은 코드가 많이 있습니다. 예를 들어 FieldByName 및 ASXXX 등, 특히 ASXXX 등은 항상 각 필드의 유형을 기억해야합니다. 또한 일부 호환되지 않는 유형을 자동으로 변환 할 수없는 경우 런타임까지 오류가 발견되지 않습니다.
2. 루프에서 현재 레코드 움직임을 직접 처리해야합니다. 위의 다음과 같이,이 문제는 잊어 버리면 죽은 루프가 발생합니다.
3. 가장 중요한 것은 필드 이름이 문자열 매개 변수를 잘못 기록하면 런타임까지 발견되지 않으므로 잠재적 인 버그의 가능성이 증가합니다. FieldByName, 그러한 문제가 고객에게 지연되는 경우에만 나타날 수 있습니다. 이러한 종류의 잘못된 필드 이름은 특히 프로그램이 여러 테이블을 사용하는 경우 다른 테이블의 필드 이름을 혼동하기 쉽습니다.
이 시대에 OO가 통치 한이 시대는 데이터 세트와 관련된 작업을 수행 할 때 여전히 위에서 언급 한 관계형 데이터베이스의 세부 사항에 빠져야합니다. 물론, 지금 그들을 제거 할 수있는 방법, 즉 O/R 매핑이지만 O/R 매핑은 결국 기존 개발 방법과는 너무 다르며, 특히 일부 소규모 응용 프로그램의 경우 과장 할 필요가 없습니다. 이 경우, 우리에게 필요한 것은 간단한 데이터 세트 객관화 체계입니다.
Java 및 기타 동적 언어에서 영감을 얻은 저는 Delphi의 강력한 RTTI를 사용 하여이 간단한 데이터 세트 객관화 체계를 구현하는 것을 생각했습니다. 다음은 기존 코드와 동일한 함수를 구현하는 데이터 세트 객관화 된 응용 프로그램 코드입니다.
tdspemployee = class (tmdatasetproxy) 게시 된 속성 INDECT : getInteger write setInteger; setVariant; procedure tform1.listclick (발신자 : tobject); var emp : = tdspemployee.create (adodataset1); (Emp.Employeeid); Emp.free; 끝;
사용법은 매우 간단합니다. 가장 중요한 것은 먼저 게시 된 속성을 사용하여 유형을 포함한 모든 필드를 정의 한 다음 객체 방식으로 데이터 세트를 조작 할 수있는 프록시 클래스를 먼저 정의하는 것입니다. 이 프록시 클래스는 TMDATASETPROXY에서 파생되며 RTTI를 사용하여 속성 작업에서 현장 작업으로 매핑을 구현하면 해당 단위를 사용합니다. 이 클래스의 구현 단위는 아래에 자세히 설명됩니다.
표면적으로는 더 많은 코드가있는 것처럼 보이는 데이터 세트를 정의하는 추가 프록시 클래스가 있지만, 특히 프로그램이 동일한 데이터 세트의 구조를 여러 번 재사용 해야하는 경우 일회성입니다. 만들어 질 것입니다. 또한이 프록시 클래스의 정의는 매우 간단합니다. 속성 액세스 함수 getxxx/setxxx는 모두 기본 클래스 tmdatasetproxy에서 구현됩니다.
이제 원래 코드에 해당하는 루프를 살펴 보겠습니다.
1. FieldByName 및 ASXXX는 필요하지 않으며 프록시 클래스에서 속성 작업이되었습니다. 또한 각 필드에 해당하는 속성 유형이 이전에 정의되었으므로 사용할 때마다 어떤 유형이 있는지 고려할 필요가 없습니다. IT. 잘못된 유형을 사용하면 편집 중에 오류가보고됩니다.
2. Foreach를 사용하여 레코드 트래버스를 수행하고 더 이상 다음에 발생하는 악순환을 잊어 버릴 필요가 없습니다.
3. 가장 큰 장점은 필드 이름이 속성이되므로 프록시 클래스를 정의 할 때 필드 이름이 잘못 작성되지 않으면 컴파일 시간에 필드 이름을 찾을 수 있습니다.
이제 tmdatasetproxy에 대해 논의하십시오. 구현 코드는 다음과 같습니다.
(************************************************* ******************* rtti와 함께 구현 된 데이터 세트 프록시는 DataSet (c) 2005를 간단히 객관화 할 수 있습니다날짜 : 1 월 28-05 ************************************* *****************) 단위 mdspcomm; 인터페이스 클래스, db, typinfo; type tmproplist = class (tobject) 개인 fpropcount : pproplist; (index : aindex : ppropinfo는 aobj : tpersistent; Propinfo는 getprop를 읽습니다 가상; aindex; 가상; : tdataset; classinfo)^. fpropcount> 0을 시작한다 (FPROPLIST) 그런 다음 FREEMEM (fproplist); tmproplist.getPropName (aindex : Integer) : Shortstring; 시작 : = getProp (aindex)^. end; {tmrefdataset} create (adataset : tdataset); flooping; end; fdataset.close는 fproplist를 시작한다. 끝; 절차 tmdatasetproxy.beginedit; if (fdataset.state <> dsedit) 및 (fdataset.state <> dsinsert) 그런 다음 fdataset.edit; end; 절차 tmdatasetproxy.endrit; 시작 if (fdataset.state = dsedit) 또는 (fdataset)를 시작합니다. .State = dsinsert) 그런 다음 fdataset.post; end; 함수 tmdatasetproxy.getinteger (aindex : integer) : = fdataset.fieldbyname (fproplist.propnames [aindex]) : 정수) : Double; 시작 결과 : = fdataset.fieldByName (fproplist.propNames [aindex]) .Asfloat; end; function tmdatasetproxy.getstring (aindex : intger) : string; result : = fdataset.fieldbyName (fproplist .propnames .propnames .propnames. aindex])). ASSTRING; END; 함수 TMDATASETPROXY.GETVARINT (AINDEX : INTEGER) : 변형; 시작 결과 : = FDATASET.FIELDBYNAME (FPROPLIST.PROPNAME [AINDEX]). 값; end; 절차 TMDATASETPROXY.SETINTEGER (AVULGE, AVULGER, AVULGER ); fdataset.field.PropName [aindex] ]) .asfloat : = avalue; end; 절차 tmdatasetproxy.setString (aindex : avalue : string); fproplist.fieldbyname [aindex] .ASSTRING : = AVALUE; index : avalue; fdataset endedit; fdataset.eof가 아닌 경우;
TMPROPLIST 클래스는 RTTI 속성 작업의 일부 기능을 캡슐화 한 것입니다. 이 기능은 TypInfo 장치에서 Delphi가 정의한 일부 RTTI 기능을 사용하여 게시 된 속성 목록 정보를 유지하기 위해 tpersistent 파생 클래스를 구현하는 것입니다. 프록시 클래스는이 속성 목록을 통해 속성 이름을 얻고 마지막 으로이 속성 이름과 데이터 세트의 해당 필드를 통해 작동합니다.
tmdatasetproxy는 데이터 세트 프록시 클래스의 기본 클래스입니다. 가장 중요한 부분은 애프터 건설에서 속성 목록을 만드는 것입니다.
속성의 작동은 정수, 더블/플로트, 문자열 및 변형의 네 가지 데이터 유형만을 구현합니다. 필요한 경우이 기준으로 자신의 프록시베이스 클래스를 도출하여 다른 데이터 유형의 구현을 구현할 수 있으며, 이러한 구현 된 유형의 속성 구현은 가상 기능으로 정의 될 수 있습니다. 교체의 구현. 그러나 일반적으로 사용되지 않은 유형의 경우 구현하기 전에 실제 프록시 클래스를 정의하는 것이 좋습니다. 예를 들어, 이전 예에서는 tdateTime이 일반적으로 사용되는 유형이 아니라고 가정하면 다음을 수행 할 수 있습니다.
tdspemployee = class (tmdatasetproxy) GetDateMe (const index : indeger); GetString Write SetString; String Index 2 GetString Write SetString; (getVariant (index)); end; procedure tdspemployee.SetDateTime (const index; const value);
이런 식으로, 생년월일을 tdateTime 유형으로 직접 사용할 수 있습니다.
또한이를 활용하면 일부 사용자 정의 특수 데이터 유형에 대해 통합 작업을 제공 할 수 있습니다.
또한 DataSet.edit을 사용하는 것을 잊어 버려 런타임 오류를 피하기 위해 모든 SETXXX 전에 BeginedIT가 호출되었습니다.
Foreach는 각 Foreach가 트래버스를 완료하면 현재 레코드가 다음 루프의 첫 번째 레코드로 이동합니다. 또한 Endedit은 변경 사항을 자동으로 제출하기 전에 호출됩니다.
이 데이터 세트 객관화 체계는 매우 간단한 솔루션입니다. 가장 큰 문제는 속성의 인덱스 매개 변수가 정의 될 때 속성 순서대로 엄격하게 있어야한다는 것입니다. 델파이는 여전히 기본 개발 언어이기 때문입니다. 동적이 없으므로 현재 메소드를 사용하여 등록 할 수 있습니다.