#delphi #generics #dictionary #delphi-xe
#delphi #общие #словарь #delphi-xe
Вопрос:
Можно ли использовать унаследованный интерфейс в качестве ключа в TDictionary?
//! Note the inheritance of the interfaces
ILoggingProvider = interface
procedure Log(AMessage : string);
end;
IHTTPLoggingProvider = interface(ILoggingProvider)
function Login(AUserName : string; APassword : string) : boolean
end;
ILiveLoggingProvider = interface(ILoggingProvider)
function ConnectMonitor : boolean
end;
var
loggers : TDictionary<ILoggingProvider,TObject>;
...
loggers.add(ILoggingProvider, TSomeLogger.Create());
loggers.add(IHTTPLoggingProvider , TSuperLogger.Create()); //fails!
loggers.add(ILiveLoggingProvider , TAnotherLogger.Create()); //fails!
... //and the use them selectively
if loggers.ContainsKey(IHTTPLoggingProvider ) then
loggers.Items[IHTTPLoggingProvider].Log('Good bye world!');
... //and like this
var
theLogger : IHTTPLoggingProvider;
if loggers.ContainsKey(IHTTPLoggingProvider ) then
begin
theLogger := IHTTPLoggingProvider(loggers.Items[IHTTPLoggingProvider]);
if theLogger.Login('billy', 'bones') then
theLogger.Log('some message');
end;
Комментарии:
1. Конечно
TDictionary<ILoggingProvider,TObject>
, нужны ссылки на интерфейс, а не интерфейсы. И приведениеTObject
кIHTTPLoggingProvider
очень сомнительно. Тип значения должен быть интерфейсом. Я бы сделал ключ идентификатором GUID, я думаю. Или я ухватился не за тот конец палки?2. @David: Правильное использование интерфейсов также будет работать и будет более последовательным при использовании подхода с чистыми интерфейсами — хорошая идея. Когда я объявляю
TLoggers = TDictionary<TGUID,ILoggingProvider>
, это вызывает исключениеInvalid type cast
при создании экземпляра ‘TLoggers’, в то времяloggers := TDictionary<TGUID,ILoggingProvider>.Create
как word fine. Есть идеи?3. Код в моем ответе компилируется, запускается и работает правильно.
Ответ №1:
Следуя моему комментарию, вот как, я думаю, это можно было бы реализовать:
type
ILoggingProvider = interface
['{30598F45-1230-4208-B1A5-E1D2DA8F6D40}']
procedure Log(AMessage : string);
end;
IHTTPLoggingProvider = interface(ILoggingProvider)
['{CFA01514-AC44-4E30-971B-115986B37D26}']
function Login(AUserName : string; APassword : string) : boolean;
end;
ILiveLoggingProvider = interface(ILoggingProvider)
['{6EA68BEF-8D78-4FDF-AACD-1D164A272758}']
function ConnectMonitor : boolean;
end;
TLoggingProvider = class(TInterfacedObject, ILoggingProvider)
procedure Log(AMessage : string);
end;
THTTPLoggingProvider = class(TInterfacedObject, ILoggingProvider, IHTTPLoggingProvider)
procedure Log(AMessage : string);
function Login(AUserName : string; APassword : string) : boolean;
end;
TLiveLoggingProvider = class(TInterfacedObject, ILoggingProvider, ILiveLoggingProvider)
procedure Log(AMessage : string);
function ConnectMonitor : boolean;
end;
procedure Main;
var
loggers : TDictionary<TGUID,ILoggingProvider>;
theLogger : IHTTPLoggingProvider;
begin
loggers := TDictionary<TGUID,ILoggingProvider>.Create;
try
loggers.add(ILoggingProvider, TLoggingProvider.Create);
loggers.add(IHTTPLoggingProvider, THTTPLoggingProvider.Create);
loggers.add(ILiveLoggingProvider, TLiveLoggingProvider.Create);
if loggers.ContainsKey(IHTTPLoggingProvider) then
loggers.Items[IHTTPLoggingProvider].Log('Good bye world!');
if loggers.ContainsKey(IHTTPLoggingProvider) then
begin
theLogger := loggers.Items[IHTTPLoggingProvider] as IHTTPLoggingProvider;
if theLogger.Login('billy', 'bones') then
theLogger.Log('some message');
end;
finally
loggers.Free;
end;
end;