Reputation: 9431
A TDictionary is assigned to an TObject variable. I can cast the TOBject back to a TDictionary in the same project. However if the cast is done in a referenced bpl project the cast fails depending on how the project is referenced.
The test code:
procedure TestTDefault.Test1;
var
Obj: TObject;
begin
Obj := TDictionary<string, Integer>.Create;
Check(Obj is TDictionary<string, Integer>);
CheckNotNull(Obj as TDictionary<string, Integer>);
// this calls the function in the referenced bpl package.
// Returns True if Obj can be cast back to a TDictionary.
CheckTrue(TestIfDictionary(Obj)); // outcome depends if referenced packge is included in <DCC_UsePackage>
end;
The function in the dependent package:
function TestIfDictionary(aObject: TObject): Boolean;
begin
Result := aObject is TDictionary<string,Integer>;
end;
I have a simple project group with only two packages:
Both packages have the same compiler/linker options set.
What is very odd is that the test works only if Package1 is NOT listed as a runtime package:
However test fails if Package1 is listed a runtime package!!
I am using XE2. As to the purpose, this issue surfaced when dealing with RTTI. I was able to isolate the problem in this simple Test project. Problem has nothing to do with RTTI. Just as a note, if instead of using a TDictionary I use a TStringList, then test always works. So problem seems to be somehow related to generics. If needed I can make the simple test project available.
I have spent quite some time tracking down this problem. I am happy that I got to discover what triggers the problem. But unfortunately I can just not understand why this happens.
Upvotes: 3
Views: 177
Reputation: 613272
The problem you have here is related to generic instantiation. Each module is separately instantiating the generic type, and so they have different type identity. This is a basic limitation of the design of generics, and its interaction with runtime packages.
You could instantiate the generic type in a unit in the package, for instance like this:
type
TDictionaryStringInteger = class(TDictionary<string, Integer>);
And then use TDictionaryStringInteger
in place of TDictionary<string, Integer>
. However, this pretty much cripples your code as it stops you writing generic methods that use generic types.
The other way out of your bind is to stop using runtime packages. Frankly, that seems rather more attractive to me.
Upvotes: 1
Reputation: 2940
You should use type declaration for this generic class.
type
Tx = TDictionary<string, Integer>;
....
Obj := Tx.Create;
Check(Obj is Tx);
RTTI doesn't matter in your case.
Upvotes: 0