Delphi - Interface inheritance with generics

后端 未结 1 1969
北恋
北恋 2021-01-12 12:02

I am currently stuck with a compiling error, no one in our company can help and I am sadly not finding the correct search patterns for SO or google.

As code I am us

相关标签:
1条回答
  • 2021-01-12 12:35

    Update

    The original question had a problem which I identified (see below). However, the fix I describe there is fine for XE3 and later, but that program below does not compile in XE2. Thus I conclude that this is an XE2 generics compiler bug.

    Anyway, here's a workaround for Delphi XE2:

    {$APPTYPE CONSOLE}
    type
      IStorageObject = interface(IInterface)
      end;
      TObjectStorage<T: IStorageObject> = class(TObject)
      end;
      IKeyStorageObject<TKey> = interface(IStorageObject)
      end;
      TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>, IStorageObject> = class(TObjectStorage<T>)
      end;
      TImplementingClass<TKey> = class(TInterfacedObject, IStorageObject, IKeyStorageObject<TKey>)
      end;
    begin
      TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create;
    end.
    

    Original answer

    It would have been better if you had provided a complete program that exhibited the compiler error. You need to attempt to instantiate an object to see that error.

    But, I think I've reproduced your problem. So I believe that the issue is that this code:

    TKeyObjectStorage<TKey, T: IKeyStorageObject<TKey>> = ...
    

    applies the generic constraint to both TKey and T. Now, clearly you only want the constraint to apply to T so you'll need to write:

    TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = ...
    

    Here's a short program that compiles following the change in Delphi XE3:

    {$APPTYPE CONSOLE}
    type
      IStorageObject = interface(IInterface)
      end;
      TObjectStorage<T: IStorageObject> = class(TObject)
      end;
      IKeyStorageObject<TKey> = interface(IStorageObject)
      end;
      TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = class(TObjectStorage<T>)
      end;
      TImplementingClass<TKey> = class(TInterfacedObject, IKeyStorageObject<TKey>)
      end;
    begin
      TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create;
    end.
    

    This is quite a nuance, the changing of a comma to a semi-colon. Programming by significant punctuation is never much fun. That said, you are familiar with the difference between commas and semi-colons in formal parameter lists and so it should not come as too much of a surprise to see the same distinction drawn here.

    The documentation does cover this mind you:

    Multiple Type Parameters

    When you specify constraints, you separate multiple type parameters by semicolons, as you do with a parameter list declaration:

    type
      TFoo<T: ISerializable; V: IComparable>
    

    Like parameter declarations, multiple type parameters can be grouped together in a comma list to bind to the same constraints:

    type
      TFoo<S, U: ISerializable> ...
    

    In the example above, S and U are both bound to the ISerializable constraint.

    0 讨论(0)
提交回复
热议问题