Does the generic interface contain the name of the interface?

Basically, I want the class to be able to implement two different versions of the same common interface.

Consider this code

type // a generic interface ITest<T> = interface ['{6901FE04-8FCC-4181-9E92-85B73264B5DA}'] function Val: T; end; // a class that purports to implement two different types of that interface TTest<T1, T2> = class(TInterfacedObject, ITest<T1>, ITest<T2>) protected fV1: T1; fV2: T2; public constructor Create(aV1: T1; aV2: T2); function Val: T1; // Val() for ITest<T1> function T2Val: T2; // Val() for ITest<T2> function ITest<T2>.Val = T2Val; // mapping end; constructor TTest<T1, T2>.Create(aV1: T1; aV2: T2); begin inherited Create; fV1 := aV1; fV2 := aV2; end; function TTest<T1, T2>.T2Val: T2; begin result := fV2; end; function TTest<T1, T2>.Val: T1; begin result := fV1; end; ///////////// procedure Test; var t : TTest<integer, string>; begin t := TTest<integer, string>.Create(39, 'Blah'); ShowMessage((t as ITest<string>).Val); // this works as expected ShowMessage(IntToStr((t as ITest<integer>).Val)); // this gets AV end; 

The first ShowMessage displays β€œBlah,” as you would expect, but the second crashes. The reason it crashes is because the call calls T2Val () instead of Val (), as I expected. Apparently, conflict resolution mapping displays a method for both types of interfaces, not just ITest: T2.

So, here is my question (s).

This is mistake? By this, I mean that Embarcadero intends to support this and simply implement it incorrectly? Or did they never have the intention of letting programmers do something like that? (Honestly, I was a little surprised that my test program even compiled)

If this is a mistake, can anyone understand if there can be a workaround to allow me to have one class supporting two different types of one common interface?

+6
generics delphi delphi-2010
source share
2 answers

as with an interface type, an interface listing is used that uses a GUID to search for an interface. For a common interface with a GUID, each instance receives the same GUID. If one type implements multiple copies of the interface, then a GUID search will return the first interface.

The program works as expected if you are not using an interface listing, but instead use an interface transformation as follows:

 procedure Test; var t : TTest<integer, string>; begin t := TTest<integer, string>.Create(39, 'Blah'); ShowMessage(ITest<string>(t).Val); ShowMessage(IntToStr(ITest<Integer>(t).Val)); end; 

Initially, when generic tools were run for Win32, GUIDs were not allowed on common interfaces. However, a dynamic query for common interfaces was desirable for common container scenarios and, in general, as a service provider request mechanism for type services in the context of an algorithm (e.g. sorting or searching, which requires things like comparisons and equality tests ) Thus, a new plan was formed: to have a GUID for the common interface, but to create a hash of type arguments for shared instances and collapse (for example, xor) the hash in the GUID to create a unique GUID for each separate and incompatible instance. However, it was late that day, and good implementation was not possible for a time. But the requirement for dynamic queries remained, so the GUIDs remained. That is why everything is as it is today.

To solve your specific scenario, the best thing I recommend is to use separate descendants with explicit GUIDs; or use another mechanism to request an interface.

+11
source share

This is an interesting problem. What seems to be happening is that the compiler always maps the interface to the last specified version of the interface (if you change the order, then it calls another method). This may be due to the fact that both interfaces have the same GUID signature, so the dispatcher gets confused as to which method should be called when he sees the interface call.

This seems to be a mistake, so it should be reported through a quality central one.

+3
source share

All Articles