How a class can inherit from one interface and another class in Delphi

0

I am creating a small persistence class using RTTI. I created the attributes of the fields separated by type Ex: FieldString [], FieldInteger [], and so on. At some point I need to go through the attributes to find a particular field, and that's the question. Currently the way it is, I would have to first check if the attribute is FieldString [], FieldInteger [], and then compare with the 'Name' property that each class has. So I thought about creating an IField type interface with the property 'Name' and then I would cast it. The problem is that classes have to implement TCustomAttribute, Ex:

IField = interface
..
  property Name:string read GetName write SetName;
  property IsPk:string read GetIsPk write SetIsPk;
end;

TFieldString = class(TCustomAttribute, IField) 
...
  property Name:string read GetName write SetName;
  property IsPk:string read GetIsPk write SetIsPk;
end.

TFieldInteger = class(TCustomAttribute, IField) 
...
  property Name:string read GetName write SetName;
  property IsPk:string read GetIsPk write SetIsPk;
end.

And I do not know how to do this.

    
asked by anonymous 27.07.2015 / 18:53

3 answers

0

Attributes in Delphi are just classes, when you write a language construct with an attribute, what you do is instantiate a class and link it to the construct for use by RTTI. So you can avoid the interface (which in fact will only be for you headache) through an ancestor, as follows:

TFieldAttribute = class(TCustomAttribute)
private
  FName: string;
  FisPk: Boolean;
public
  constructor Create(const aName: string; aIsPk: Boolean=False);
  property Name:string read FName write FName;
  property IsPk: Boolean read FIsPk write FIsPk;
end;

TFieldStringAttribute = class(TFieldAttribute) 
end;

TFieldIntegerAttribute = class(TFieldAttribute) 
end;

And so for all attributes, however, I do not understand why you need specific attributes by type, since Rtti already gives you the typing of each property. In your place I would only have the ancestral attribute ( TFieldAttribute ) to identify each of the mapped properties and would use the type of that property itself to map to your persistence medium.

Now, if you have cases where there are different types between the Delphi property and the column in the database, then what you can do is create one more parameter in the attribute to say this. For example:

TFieldAttribute = class(TCustomAttribute)
private
  FName: string;
  FColumnType: string
  FIsPk: Boolean;
public
  constructor Create(const aName: string; aIsPk: Boolean=False); overload;
  constructor Create(const aName, aColumnType: string; aIsPk: Boolean=False); overload;
  property Name:string read FName write FName;
  property ColumnType: string read FColumnType write FColumnType;
  property IsPk: Boolean read FIsPk write FIsPk;
end;

In particular, I would have a proper PK attribute. Here it would be:

TFieldAttribute = class(TCustomAttribute)
private
  FName: string;
  FColumnType: string
public
  constructor Create(const aName: string); overload;
  constructor Create(const aName, aColumnType: string); overload;
  property Name:string read FName write FName;
  property ColumnType: string read FColumnType write FColumnType;
end;

TPrimaryKeyAttribute = class(TFieldAttribute)
end;

Then in your code you need to test the attribute type using the is operator. In the case of a person type class (typical example) would be:

TPessoa = class
private
  [PrimaryKey('Id')]
  FId: Long;
  [Field('Nome')]
  FNome: string;
  [Field('Dt_Nasc', 'VARCHAR')]
  FNascimento: TDateTime;
public
  property Id: Long read FId;
  property Nome: string read FNome write FNome;
  property Nascimento: TDateTime read FNascimento write FNascimento;
end;

I imagine this will serve you!

    
28.07.2015 / 14:43
0

I'm not sure I understand your question (and I can not comment on my reputation), but I'll try to answer for my understanding of the initial question.

Delphi does not support multiple inheritance, but classes can implement multiple interfaces and you can delegate interface execution so you can simulate multiple inheritance means.

Your interfaces must be declared as Interface(IInterface) and their concrete classes as class(TInterfacedObject, IInterface) . Following your example, it would look like this:

type

  IField = Interface(IInterface)
    // Declaração de métodos que deveram ser implementos pelas
    // classes que implementarem essa interface.
  end;

  TCustomAttribute = class(TInterfacedObject)
    // Declaração de métodos e atributos.
  end;

  TFieldString = class(TCustomAttribute, IField)
    // Declaração de métodos e atributos.
  end;

  TFieldInteger = class(TCustomAttribute, IField)
    // Declaração de métodos e atributos.
  end;

end.

Source: link

I hope I have helped!

    
28.07.2015 / 13:41
0

I think it's going to be clear now. For example, in assembling the insert

  for RttiProperty in RttiType.GetProperties do
    for RttiAttribute in RttiProperty.GetAttributes do
      if RttiAttribute is TTypeInteger then
      begin
        if not TTypeInteger(RttiAttribute).IsIdentity then
        begin
          strFields := strFields + TTypeInteger(RttiAttribute).Name  + ',';
          strValues := strValues + QuotedStr( IntToStr( RttiProperty.GetValue(TObject(Obj)).AsInteger ) ) + ',';
        end;
      end
      else if RttiAttribute is TTypeString then
      begin
        if Trim( RttiProperty.GetValue(TObject(Obj)).AsString ) <> '' then
        begin
          strFields := strFields + TTypeString(RttiAttribute).Name  + ',';
          strValues := strValues + QuotedStr(RttiProperty.GetValue(TObject(Obj)).AsString) + ',';
        end;
      end;
    end;

I run all attributes to get the name and value. Ok, but your self wanted to get only the field names, yet I would have to test the attribute type one by one. What I wanted is something like

if RttiAttribute is TField then
  strFields := strFields + TField (RttiAttribute).Name  + ',';

But to achieve this, the daughter class would have to implement TField and TCustomAttribute, but as it is not possible in DELPHI, I created the interface, but I still could not compile, that's when I sent the question.

    
28.07.2015 / 14:05