最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

delphi - Enumeration property redeclarationinheritance with additional value - Stack Overflow

programmeradmin3浏览0评论

I have my own class. It has an enumeration property from a base class in Data.DB:

TProviderFlag = (pfInUpdate, pfInWhere, pfInKey, pfHidden);
TProviderFlags = set of TProviderFlag;

I want to do something like this:

TMyProviderFlag = (pfInUpdate, pfInWhere, pfInKey, pfHidden, pfDummy);
TMyProviderFlags = set of TMyProviderFlag;

So, something like extra types for this enumeration.

But, it should also somehow be possible to get TMyProviderFlag.pfInUpdate as TProviderFlag.pfInUpdate, for example (pseudo code):

var my: TMyProviderFlags;
my := [pfHidden, pfDummy];
Table.Field.ProviderFlag := MyInstance.pfHidden; 
if pfDummy in MyInstance then ...

Is this possible?

Reason for such a structure - I have code already done (and it passes provider flags), and I have also some properties for fields. It would be a good idea to pass those at the same time.

I have my own class. It has an enumeration property from a base class in Data.DB:

TProviderFlag = (pfInUpdate, pfInWhere, pfInKey, pfHidden);
TProviderFlags = set of TProviderFlag;

I want to do something like this:

TMyProviderFlag = (pfInUpdate, pfInWhere, pfInKey, pfHidden, pfDummy);
TMyProviderFlags = set of TMyProviderFlag;

So, something like extra types for this enumeration.

But, it should also somehow be possible to get TMyProviderFlag.pfInUpdate as TProviderFlag.pfInUpdate, for example (pseudo code):

var my: TMyProviderFlags;
my := [pfHidden, pfDummy];
Table.Field.ProviderFlag := MyInstance.pfHidden; 
if pfDummy in MyInstance then ...

Is this possible?

Reason for such a structure - I have code already done (and it passes provider flags), and I have also some properties for fields. It would be a good idea to pass those at the same time.

Share Improve this question edited Mar 11 at 14:42 Remy Lebeau 601k36 gold badges507 silver badges851 bronze badges asked Mar 11 at 11:22 BxOOBxOO 435 bronze badges 0
Add a comment  | 

2 Answers 2

Reset to default 3

Extending an enumeration is not provided in the standard language. There are workarounds to achieve something similar, but all of them work for specific use cases and fail in others.

One way is to declare the extended enumeration type as sort of an extended subrange:

type
  TProviderFlag = (pfInUpdate, pfInWhere, pfInKey, pfHidden);
  TProviderFlags = set of TProviderFlag;

const
  {$R-}  // otherwise compiler will complain
  pfDummy = Succ(pfHidden);

type
  TMyProviderFlag = pfInUpdate .. pfDummy;
  TMyProviderFlags = set of TMyProviderFlag;

Uwe Raabe's answer is correct.

And here's a different solution that works well in some other situations:

type
  TBaseEnum = (beOne, beTwo, beThree);

type
  TExtEnum = packed record
  strict private
    Value: Byte;
  public
    class operator Implicit(const ABaseEnum: TBaseEnum): TExtEnum;
    class operator Implicit(const AExtEnum: TExtEnum): TBaseEnum;
  end;

{$IF SizeOf(TBaseEnum) <> SizeOf(TExtEnum)}
{$MESSAGE Fatal 'SizeOf(TBaseEnum) <> SizeOf(TExtEnum)'}
{$ENDIF}

const
  beFour: TExtEnum = (Value: Succ(Ord(beThree)));

{ TExtEnum }

class operator TExtEnum.Implicit(const AExtEnum: TExtEnum): TBaseEnum;
begin
  if InRange(AExtEnum.Value, Ord(Low(TBaseEnum)), Ord(High(TBaseEnum))) then
    Result := TBaseEnum(AExtEnum.Value)
  else
    raise EConvertError.Create('TExtEnum cannot be converted to TBaseEnum.');
end;

class operator TExtEnum.Implicit(const ABaseEnum: TBaseEnum): TExtEnum;
begin
  Result.Value := Ord(ABaseEnum);
end;

This leaves TBaseEnum unchanged, and, under the hood, the new type TExtEnum is a superset. And this plays along well with Delphi's type system. You can do unsafe casts between the two types if you like (a byte is a byte), but you don't have to: TBaseEnum will be assignment-compatible with TExtEnum in both directions:

var
  b: TBaseEnum;
  x: TExtEnum;
begin

  b := beOne;
  x := b; // fine
  b := x; // fine

  x := beOne; // fine
  x := beTwo; // fine
  x := beThree; // fine
  x := beFour; // fine

  x := beOne; // fine
  b := x; // fine

  b := beFour; // run-time error

  x := beFour; // fine
  b := x; // run-time error

end;
发布评论

评论列表(0)

  1. 暂无评论