powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Преобразование Интерфейса в Объект. По какой причине это разумно?
16 сообщений из 16, страница 1 из 1
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007455
Artem.1st
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В Delphi 2010 появилась поддержка оператора AS для приведения интерфейсного указателя в объектный указатель. Стал возможен такой синтаксис:
Код: pascal
1.
2.
3.
l_Object := TObject(l_Interface);

l_Object := l_Interface as TObject; 


Вопрос: В каких ситуациях требуется прибегать к такому преобразованию?
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007460
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Artem.1stВ каких ситуациях требуется прибегать к такому преобразованию?

Когда ты признаёшь, что облажался как архитектор и использовал интерфейсы там, где НЕ следовало.
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007476
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Формально Дима прав
На практике такое используется, когда не хочется городить 100500 методов в интерфейсе, тот же ClassName, например, а интерфейсы используются в первую очередь для ARC
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007479
Mixrud
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Кладем интерфейс так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
procedure TCallContextWrapper.Bind<T>(name: String; value: T);
var
  v: TValue;
begin
  case PTypeInfo(TypeInfo(T))^.Kind of
    tkInterface:
      begin
        TValue.Make(@value, TypeInfo(T), v);
        BindIntf(Name, v.AsInterface, v);
      end;
    tkClass:
      begin
        v := TValue.From<T>(value);
        BindObject(Name, v.AsObject, v);
      end;
    tkInteger, tkChar, tkFloat, tkString, tkSet, tkWChar, tkLString, tkWString,
      tkVariant, tkInt64, tkUString, tkPointer:
      begin
        v := TValue.From<T>(value);
        Bind(Name, v.AsVariant)
      end
  else
    begin
      TValue.Make(@value, TypeInfo(T), v);
      BindOtherType(Name, v);
    end;
  end;
end;



Берем интерфейс так


end;
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
function TCallContextWrapper.Get<T>(name: String): T;
begin
  case PTypeInfo(TypeInfo(T))^.Kind of
    tkInterface, tkClass:
      begin
        if not FCallContext.InputObjects.FindParam(name) then
          raise Exception.Create
            (string.Format
            ('Parameter [{0}] with type {1} not found in CallContext.',
            [name, PTypeInfo(TypeInfo(T))^.name]));

        Result := FCallContext.InputObjects[name].AsItem.Get<T>;
      end
  else
    begin
      if not FCallContext.InputParams.FindParam(name) then
        raise Exception.Create
          (string.Format
          ('Parameter [{0}] with type {1} not found in CallContext.',
          [name, PTypeInfo(TypeInfo(T))^.name]));
      Result := FCallContext.InputParams[name].AsItem.Get<T>;
    end;
  end;



Широко используем директиву [WEAK]
И это будет больше похоже на работу по C# по дотнетовски. А не в стиле убогих дельфи формошлепов.


Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
procedure TCallContextWrapper.BindIntf(name: String; value: IInterface;
  v: TValue);
var
  prm: IModuleCallParam;
begin
  prm := FCallContext.InputObjects[name];
  prm.AsRTTIValue := v;
  prm.AsInterface := value;
end;

procedure TCallContextWrapper.BindObject(name: String; value: TObject;
  v: TValue);
var
  prm: IModuleCallParam;
begin
  prm := FCallContext.InputObjects[name];
  prm.AsRTTIValue := v;
  prm.AsObject := value;
end;

procedure TCallContextWrapper.BindOtherType(name: String; v: TValue);
begin
  FCallContext.InputParams[name].AsRTTIValue := v;
end;

procedure TCallContextWrapper.BindOutputIntf(name: String; value: IInterface;
  v: TValue);
var
  prm: IModuleCallParam;
begin
  prm := FCallContext.OutputObjects[name];
  prm.AsRTTIValue := v;
  prm.AsInterface := value;
end;

procedure TCallContextWrapper.BindOutputObject(name: String; value: TObject;
  v: TValue);
var
  prm: IModuleCallParam;
begin
  prm := FCallContext.OutputObjects[name];
  prm.AsRTTIValue := v;
  prm.AsObject := value;
end;

procedure TCallContextWrapper.BindOutputOtherType(name: String; v: TValue);
begin
  FCallContext.OutputParams[name].AsRTTIValue := v;
end;
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007484
Mixrud
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А вот это небезопасный код

Код: pascal
1.
2.
3.
l_Object := TObject(l_Interface);

l_Object := l_Interface as TObject; 
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007503
white_nigger
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Mixrud
А вот это небезопасный код
С какой стати? Оба варианта официально допустимы
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007506
Mixrud
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
white_nigger
Mixrud
А вот это небезопасный код
С какой стати? Оба варианта официально допустимы


Представьте себе проект, где около 1000 интерфейсов ходят между классами.
Мало того что для каждого из них будет требоваться объявление GUID (иначе плавающий AV обеспечен), так еще и код с такими жесткими приведениями и конструкциями is/as будет раздут и плохо читаем.

Что касается ARC, то заводить интерфейс, чтобы он автоматически прибил объект только, нецелесообразно. Лучше применять технику умных указателей (код не мой):

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
unit _ClassSmartPointer;

interface

uses
  SysUtils;

type
  TLifetimeWatcher = class(TInterfacedObject)
  private
    FWhenDone: TProc;
  public
    constructor Create(const AWhenDone: TProc);
    destructor Destroy; override;
  end;

  TSmartPointer<T: class> = record
  strict private
    FValue: T;
    FLifetime: IInterface;
  public
    constructor Create(const AValue: T); overload;
    class operator Implicit(const AValue: T): TSmartPointer<T>;
    class operator Implicit(const AValue: TSmartPointer<T>): T;

    property Value: T read FValue;
  end;

{ TLifetimeWatcher }
implementation

constructor TLifetimeWatcher.Create(const AWhenDone: TProc);
begin
  FWhenDone := AWhenDone;
end;

destructor TLifetimeWatcher.Destroy;
begin
  if Assigned(FWhenDone) then
    FWhenDone;
  inherited;
end;

{ TSmartPointer<T> }

constructor TSmartPointer<T>.Create(const AValue: T);
begin
  FValue := AValue;
  FLifetime := TLifetimeWatcher.Create(procedure
  begin
    if Assigned(AValue) then
      AValue.Free;
  end);
end;

class operator TSmartPointer<T>.Implicit(const AValue: T): TSmartPointer<T>;
begin
  Result := TSmartPointer<T>.Create(AValue);
end;

class operator TSmartPointer<T>.Implicit(const AValue: TSmartPointer<T>): T;
begin
  Result := AValue.Value;
end;

End.




То тогда достаточно будет такого, код мой, проект самопального MVVM на Delphi, где как раз TDbCtx.New возвращает TSmartPointer<TDbContext<TBrokerReportListItem>>;

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
procedure TBlotterModel_BrokerReport.InternalRefresh;
begin
  _entities.AddRangeItems(TDbCtx.New<TBrokerReportListItem>(
   procedure(var p: TParams)
    begin
      p.CreateParam(ftFloat, 'par_file_group_id', ptInput).Value := _currentGroupId;
    end).Value.Query());
end;



Ссори, стяжки от опыта работы на драгоценном C# остались. И на Delphi 10.2 катастрофически не хватает деревьев выражений и каррьяжей. То что делегаты и предикаты с begin end писать нужно уже привык.
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007507
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По каким только граблям люди не готовы ходить из-за лени очистить объект.
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007510
Mixrud
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rgreat,

Размер кода...

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
TBlotterModel_F405.GetLocalSet(const data: ISetListItem<TF405ListItem>)
var dbctx: TSmartPointer<TDbContext<TF405ListItem>>;
begin
   dbctx := TDbContext<TF405ListItem>.Create;
   data.AddRangeItems(dbCtx.Value.Query()); 
end;

TBlotterModel_F405.GetLocalSet(const data: ISetListItem<TF405ListItem>)
var dbctx: TDbContext<TF405ListItem>;
begin
   dbctx := TDbContext<TF405ListItem>.Create;
   try
      data.AddRangeItems(dbCtx.Query());
   finally
      data.Free;
   end; 
end;



И про слабосвязанные ссылки [WEAK] я не зря написал. Это просто экономит километры кода, связанного с подписками на сообщения о уничтожении объекта, от которого взят интерфейс.
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007511
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Mixrud
Что касается ARC, то заводить интерфейс, чтобы он автоматически прибил объект только, нецелесообразно. Лучше применять технику умных указателей

Ога. Вместо одного интерфейса давайте возьмём два левых интерфейса, и пусть они - обои два - следят за нашим объектом. Ох уж эти архитектурные астронавты...
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007512
Mixrud
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Kazantsev Alexey,

Не два, а один... И в рабочем проекте, представьте 300 плоских классов ListItem с отрисовкой, которая биндится в классы представления, а запрашивает миллиарды раз CxGrid GetStyleRow() и никаких утечек памяти

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
unit SummaryForBookListItem;

interface

uses  _ClassListItem, _EngineNullable, cxStyles, _EngineImages, _style;

Type
    TSummaryForBookListItem = Class (TListItem)
    strict private
      class Var
        styleRedBold: TStyle;
    private
      FIsRedRow: BooleanNull;
      FSTATE_TXT: StringNull;
      FINV_QNTY: IntNull;
      FRBS_QNTY: IntNull;
      FQNTY: IntNull;
    public
      function GetStyleForRow(): TCxStyle;
      property IsRedRow: BooleanNull read FIsRedRow write FIsRedRow;
      property STATE_TXT: StringNull read FSTATE_TXT;
      property INV_QNTY: IntNull read FINV_QNTY;
      property RBS_QNTY: IntNull read FRBS_QNTY;
      property QNTY: IntNull read FQNTY;
    end;

implementation

uses UITypes;

{ TSummaryForBookListItem }

function TSummaryForBookListItem.GetStyleForRow: TCxStyle;
begin
  Result := nil;
  if (FIsRedRow.HasValue and  FIsRedRow.Value) then
      Result := styleRedBold.Create(TColors.Red).FontStyle([TFontStyle.fsBold]);
end;

end.



А интерфейсы, которые следят, тут :)

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
unit _style;

interface

uses Graphics, cxStyles;

Type
  TStyle = record
  strict private
    FStyle: TCxStyle;
    FLifetime: IInterface;
  public
    Constructor Create(Color: TColor; TextColor: TColor = clBlack);
    Function FontStyle(Style: TFontStyles): TStyle;
    Function FontSize(Size: Cardinal): TStyle;
    Function FontColor(color: TColor): TStyle;
    Function FontName(Name: TFontName): TStyle;

    class operator Implicit(const Value: TStyle): Pointer;
    class operator Implicit(const Value: TStyle): TCxStyle;
  end;


implementation

uses _ClassSmartPointer;

constructor TStyle.Create(Color, TextColor: TColor);
var style: TcxStyle;
begin
  if Assigned(FStyle) then
    Exit;
  FStyle := TCxStyle.Create(nil);
  FStyle.Color := Color;
  FStyle.TextColor := TextColor;
  Style:=FStyle;
  FLifetime := TLifetimeWatcher.Create(procedure
  begin
    if Assigned(Style) then
      Style.Free;
  end);
end;

function TStyle.FontColor(color: TColor): TStyle;
begin
  if Assigned(FStyle) then
    FStyle.Font.Color := Color;
  Result := Self;
end;

function TStyle.FontName(Name: TFontName): TStyle;
begin
  if Assigned(FStyle) then
    FStyle.Font.Name := Name;
  Result := Self;
end;

function TStyle.FontSize(Size: Cardinal): TStyle;
begin
  if Assigned(FStyle) then
    FStyle.Font.Size := Size;
  Result := Self;
end;

function TStyle.FontStyle(Style: TFontStyles): TStyle;
begin
  if Assigned(FStyle) then
    FStyle.Font.Style := Style;
  Result := Self;
end;

class operator TStyle.Implicit(const Value: TStyle): TCxStyle;
begin
  Result := Value.FStyle;
end;

class operator TStyle.Implicit(const Value: TStyle): Pointer;
begin
  Result := Value.FStyle;
end;


end.
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007513
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Mixrud
Не два, а один...

В приведённом примере сматрпоинтера - два.
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007516
Mixrud
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Kazantsev Alexey,

А вы внимательный. Анонимный метод неявно оборачивается в интерфейс. Два интерфейса, совершенно точно.
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007520
white_nigger
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И зачем такие навороты при наличии репозитария стилей? Пусть в нем создаются ре-используются (+визуальщина) и им же прибьются...
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007544
Artem.1st
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU
На практике такое используется, когда не хочется городить 100500 методов в интерфейсе, тот же ClassName

Спасибо.

Mixrud
Код: pascal
1.
procedure TCallContextWrapper.Bind<T>(name: String; value: T);



М.б. ... это реализация “умного указателя”, который можно удалить вручную?
Код выглядит интересно, но добавить бы в начало (1 строку)комментарий - общую идею, что он делает.

Mixrud
для каждого из них будет требоваться объявление GUID (иначе плавающий AV обеспечен)

Можно простой пример: Как возникнет AV, если убрать GUID?
И что Вы называете “плоскими” классами? 22212342
...
Рейтинг: 0 / 0
Преобразование Интерфейса в Объект. По какой причине это разумно?
    #40007557
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Mixrud,

white_nigger правильно заметил, для стилей\ресурсов более характерно CreateOnce
и ещё более важна возможность подменить стиль\ресурс в использующих модулях
...
Рейтинг: 0 / 0
16 сообщений из 16, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Преобразование Интерфейса в Объект. По какой причине это разумно?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]