RTTI properties not returned for fixed enumerations: is it a bug?

Deadly 提交于 2019-12-11 02:54:27

问题


I need to browse all published properties of some classes. Properties where the type is an enumeration with fixed values are not listed.

See example below:

TMyEnum = (meBlue, meRed, meGreen);
TMyEnumWithVals = (mevBlue=1, mevRed=2, mevGreen=3);
TMyClass =
...
published
  property Color: TMyEnum read FColor write SetColor; // This one is found
  property ColorVal: TMyEnumWithVals read FColorVal write SetColorVal; // This one is never found
end;

I need fixed values because these properties are stored in a database and I need to ensure that allocated values will always be the same, regardless of Delphi compiler choices in next versions, and prevent any misplaced insert of future values in the enumeration list.

I tried with both new Delphi 2010 RTTI (with .GetDeclaredProperties) and "old" RTTI (with GetPropInfos): all properties are found except the above type of property.

The same behaviour is seen on all classes. I also reproduced this in a sample project.

Tried with and without various RTTI directives without change.

Is this a bug, a known limitation? Is there a workaround (except removing fixed values of the enumeration)?

Using Delphi2010 Ent+Update5

[Edit] The answer below provides the workaround: The first value of the enumeration must be set to 0 instead of 1, and values contiguous. Tested and working solution.

Thanks,


回答1:


Barry Kelly says:

Discontiguous enumerations and enumerations which don't start at zero don't have typeinfo. For typeinfo to be implemented, it would need to be in a different format from the existing tkEnumeration, owing to backward compatibility issues.

I considered implementing a tkDiscontiguousEnumeration (or possibly better named member) for Delphi 2010, but the benefit seemed small considering their relative scarcity and the difficulties in enumeration - how do you encode the ranges efficiently? Some encodings are better for some scenarios, worse for others.

So it's not a bug, but a known limitation.




回答2:


This is a limitation. Enumerated types with explicit ordinality can not have RTTI. Documented here.

Possible solution is to declare Reserved values within your enumerated type, eg:

TMyEnum = (meReserved1, meBlue, meRed, meGreen, meReserved2, meWhite); // and so on
...
Assert(MyEnum in [meBlue..meGreen, meWhite], 'sanity check failed')

Practical enums tends to occupy contiguous ranges, so you probably will not end up in having declaring gazillions of reserved values. In case you are interoperating with C style bitfields you will have to split value to distinct enums and sets.




回答3:


To add some more background information, Enums with values, are treated as subrange types with predefined constants.

For example:

type
  TMyEnumWithVals = (mevBlue=1, mevRed=2, mevGreen=3);

Is treated as:

type
  TMyEnumWithVals = 1..3;
const 
  mevBlue  : TMyEnumWithVals = 1;
  mevRed   : TMyEnumWithVals = 2;
  mevGreen : TMyEnumWithVals = 3;

However, you can't combine these with integers without casting.

var
  enum   : TMyEnumWithVals;
  ival   : Integer;
begin
  enum := mevBlue;
  ival := Integer(mevRed);

To make matters worse, if you use:

type
  TTypeId  = (tidPrimary = 100, tidSecundary = 200, tidTertiary = 300);
  TTypeArray = array [TTypeID] of string;

You get an array of 201 elements, not of 3. You can use the values in between using:

var
  enum   : TTypeId  ;
  ival   : Integer;
begin
  enum := TTypeId(150);  // Is valid.

This information can be found in the Delphi language guide, with the enum type section.



来源:https://stackoverflow.com/questions/7857943/rtti-properties-not-returned-for-fixed-enumerations-is-it-a-bug

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!