2015-12-23 69 views
8

AFAIK沒有內置的功能。在網上搜索我發現這function它適用於我,但我不喜歡它,因爲它是組裝,我不明白它在做什麼。所以我寫了這個功能也可以工作:如何獲取任何類型集變量的元素數量?

function Cardinality(const PSet: PByteArray; 
    const SizeOfSet(*in bytes*): Integer): Integer; 
const 
    Masks: array[0..7] of Byte = (1, 2, 4, 8, 16, 32, 64, 128); 
var 
    I, J: Integer; 
begin 
    Result := 0; 
    for I := 0 to SizeOfSet - 1 do 
    for J := 0 to 7 do 
     if (PSet^[I] and Masks[J]) > 0 then 
     Inc(Result); 
end; 

現在,我想知道如果我能靠這個功能呢?或者也許設置數據類型背後有一個竅門,這就是爲什麼delphi沒有內置方法的原因。

if我的功能是可靠then我怎麼能就提高:

  1. 通行證常量它
  2. 做一個類型檢查,並確保一組被傳遞給函數
  3. 通行證該值,而不是它的地址
  4. 擺脫SizeOfSet參數

我想稱之爲Cardinality(AnySet)而不是Cardinality(@AnySet, SizeOf(TAnySet))

順便說一句,我需要在XE和XE5中編譯這個。

回答

5

你可以用泛型和RTTI來實現這一點。像這樣:

uses 
    SysUtils, TypInfo; 

type 
    ERuntimeTypeError = class(Exception); 

    TSet<T> = class 
    strict private 
    class function TypeInfo: PTypeInfo; inline; static; 
    public 
    class function IsSet: Boolean; static; 
    class function Cardinality(const Value: T): Integer; static; 
    end; 

const 
    Masks: array[0..7] of Byte = (1, 2, 4, 8, 16, 32, 64, 128); 

implementation 

{ TSet<T> } 

class function TSet<T>.TypeInfo: PTypeInfo; 
begin 
    Result := System.TypeInfo(T); 
end; 

class function TSet<T>.IsSet: Boolean; 
begin 
    Result := TypeInfo.Kind=tkSet; 
end; 

function GetCardinality(const PSet: PByteArray; 
    const SizeOfSet(*in bytes*): Integer): Integer; inline; 
var 
    I, J: Integer; 
begin 
    Result := 0; 
    for I := 0 to SizeOfSet - 1 do 
    for J := 0 to 7 do 
     if (PSet^[I] and Masks[J]) > 0 then 
     Inc(Result); 
end; 

class function TSet<T>.Cardinality(const Value: T): Integer; 
var 
    EnumTypeData: PTypeData; 
begin 
    if not IsSet then 
    raise ERuntimeTypeError.Create('Invalid type in TSet<T>, T must be a set'); 
    Result := GetCardinality(PByteArray(@Value), SizeOf(Value)); 
end; 

用法:

Writeln(TSet<SomeSet>.Cardinality(Value)); 
+0

謝謝,但XE並不編譯:** E2506在接口部分聲明的參數化類型的方法不能使用本地符號'GetCardinality'**。所以我必須將'GetCardinality'定義爲類函數。同樣的問題關於'面具'。這些更改後,它運行並正常工作。 – saastn

+1

是的,這是舊編譯器中的編譯器缺陷。如果需要,可以手動內聯該功能。無論如何,這個概念是完美的。 –

2

在早期的Delphi的版本,你可以這樣做:

function Card(ASet: TSet): Integer; 
var 
    k: TSetElement; 
begin 
    Result := 0; 
    for k in ASet do Inc(Result); 
end; 
+0

您在代碼中定義的「TSet」和「TSetElement」通用類型或類型? – saastn

相關問題