Delphi Generics> Словарь со значением по умолчанию - PullRequest
5 голосов
/ 23 октября 2010

Я хотел бы иметь словарь, который возвращает значение по умолчанию, когда ключ поиска не найден. Чтение из документации:

Generics.Collections.Tdictionary […] Этот класс обеспечивает отображение […] и исходный контент.

1 - Как? Есть ли способ сделать это ала Python: {1: «один»; 2: ’two’}?

Generics.Collections.TDictionary.TryGetValue [...] TryGetValue возвращает true, если данный ключ находится в словаре и предоставляет его значение в Value. В противном случае возвращается значение false, а для параметра Value устанавливается значение по умолчанию типа Tvalue.

2 - Как установить значение по умолчанию? Я не могу найти конструктор (возможно, я просто искал не в том месте. Я ожидаю что-то вроде «конструктор Create (DefaultValue: TValue);»)

Итак, я пытаюсь реализовать свой собственный (может быть, это и не нужно. См. Выше):

Код (отзывы и предложения приветствуются!):

unit Util;

interface

uses
    Generics.collections;

type

    //
    // Dictionary with default response
    //
    TDefaultDictonary<K, V> = class(TObjectDictionary<K, V>)
    private
        M_DefaultValue : V;

    public
        constructor Create(Defaultvalue : V);
        destructor Destroy; reintroduce;
        function GetDefaultValue : V;
        function TryGetValue(const Key: K; out Value: V): Boolean;
        function GetValueOf(const Key: K) : V;
    end;

implementation

//
// Contructor and destructor
//
constructor TDefaultDictonary<K, V>.Create(Defaultvalue : V);
begin
    inherited Create;

    M_DefaultValue := Defaultvalue;
end;

destructor TDefaultDictonary<K, V>.Destroy;
begin
    inherited Destroy;
end;

//
// Get the default Value
//
function TDefaultDictonary<K, V>.GetDefaultValue : V;
begin
    Result := M_DefaultValue;
end;


//
// Try to get a value from the dictionary for the given key.
//
// If the value is found then "Value" holds it and the function returns true.
// If the value is not found then "Value" holds the default value and the
// function returns false.
//
function TDefaultDictonary<K, V>.TryGetValue(const Key: K; out Value: V): Boolean;
var
    IsKeyFound : boolean;
    DictVal : V;

begin
    IsKeyFound := inherited TryGetValue(Key, DictVal);
    if not IsKeyFound then begin
        DictVal := M_DefaultValue;
    end;

    // Outputs:
    Value := DictVal;
    Result := IsKeyFound;
end;


//
// Get a value from the dictionary for the given key.
//
// If the value is found then the function returns it.
// If the value is not found the function returns the default value.
//
function TDefaultDictonary<K, V>.GetValueOf(const Key: K) : V;
var
    DictVal : V;

begin
    TryGetValue(Key, DictVal);

    Result := DictVal;
end;

И тесты:

unit Test_Utils;
{
    Test the TDefaultDictionary functionality
}

interface

uses
    Sysutils, Math, TestFramework, Util;

type

    TestUtil = class(TTestCase)

    public
        procedure SetUp; override;
        procedure TearDown; override;

    published
        procedure TestDefaultDictionaryGetDefaultResponse;
        procedure TestDefaultDictionaryExistingKey;
        procedure TestDefaultDictionaryNotExistingKey;

    end;


implementation


procedure TestUtil.SetUp;
begin
end;

procedure TestUtil.TearDown;
begin
end;


procedure TestUtil.TestDefaultDictionaryGetDefaultResponse;
var
    dd : TDefaultDictonary<integer, string>;

begin
    dd := TDefaultDictonary<integer, string>.Create('Default response');
    checkEquals('Default response', dd.GetDefaultValue);

    dd.Free;
end;

procedure TestUtil.TestDefaultDictionaryExistingKey;
var
    dd : TDefaultDictonary<integer, string>;
    outVal : string;
    isKeyFound : boolean;

begin
    dd := TDefaultDictonary<integer, string>.Create('Default response');
    dd.Add(1, 'My one');

    checkEquals(1, dd.Count,
        'One element as count');

    isKeyFound := dd.TryGetValue(1, outVal);
    check(isKeyFound,
        'Key not found by TryGetValue');

    checkEquals('My one', outVal,
        'Value given by TryGetValue');  

    checkEquals('My one', dd[1],
        'Value given by indexing as array');

    dd.Free;
end;


procedure TestUtil.TestDefaultDictionaryNotExistingKey;
var
    dd : TDefaultDictonary<integer, string>;
    outVal : string;
    isKeyFound : boolean;

begin
    dd := TDefaultDictonary<integer, string>.Create('Default response');
    dd.Add(1, 'one');

    isKeyFound := dd.TryGetValue(2, outVal);
    check(not isKeyFound,
        'Key should not be found by TryGetValue');

    checkEquals('Default response', outVal,
        'Default Value given by TryGetValue');

    checkEquals('Default response', dd.GetValueOf(2),
        'Default Value given by indexing as array');

    //
    // It is possible to oveload the indexer operator?
    // Please review or delete me !
    //
    //checkEquals('Default response', dd[2],
    //        'Value given by indexing as array');
    //

    dd.Free;
end;


initialization
    RegisterTest(TestUtil.Suite);
end.

Это далеко не завершено. Я хотел бы, чтобы оператор индексатора также работал (см. Последний тест). Это возможно? Что также должно быть реализовано?

Утверждает ли эта реализация M_DefaultValue (я новичок в Delphi). Я не могу что-то сделать M_DefaultValue.Free в деструкторе (не настолько гибок из-за ограничений конструктора) Что здесь можно сделать?

Заранее спасибо,

Francis

Ответы [ 2 ]

1 голос
/ 23 октября 2010

Прежде чем писать весь этот код самостоятельно, вы можете посмотреть общие классы в библиотеке DeHL .

. Поддерживает это:

ТипКонцепция поддержки, которая определяет набор «классов поддержки» по умолчанию для каждого встроенного типа Delphi (используется по умолчанию в коллекциях).Пользовательские классы «поддержки типов» могут быть зарегистрированы для ваших пользовательских типов данных.

- jeroen

0 голосов
/ 28 октября 2010

Основная проблема заключается в том, что GetItem не является виртуальным в TDictionary <>. Это можно решить, просто добавив

 property Items[const Key: K]: V read GetValueOf write SetItem; default;

в ваш класс.

Кстати, деструкторы должны быть переопределены, а не повторно введены, поэтому, когда вы сохраняете его в переменной, определенной как класс более высокой иерархии, он вызывает правильный деструктор. Это просто лучшая практика, но в данном конкретном случае Items [] не будут работать так, как вы хотите, если вы это сделаете.

Благословит вас Бог.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...