How to use a generic with two different classes but one of them from the VCL












2















I am maintaining and extending a legacy app which works with 8bits bitmaps but for several reasons I did my own bitmap class from scratch (TMyBitmap) implementing some obvious features like Width, Height and ScanLine properties. Be aware that there is no relation between TBitmap and TMyBitmap (TMyBitmap doesn't inherited from TBitmap).



Now I want to do an utility class with several methods to work with either a standard TBitmap or my own TMyBitmap. The implementation of those methods is the same for a TBitmap or a TMyBitmap as they use only the "common" properties (Width, Height and ScanLine) so the generics looks like a suitable solution:



TBmpUtility<T> = class
strict private
FBmp: T;
public
constructor Create(Bmp: T);
procedure Fill(Y: Integer; Code: Byte); //example of an utility method
end;

procedure TBmpUtility<T>.Fill(Y: Integer; Code: Byte);
var
i: Integer;
Line: PByteArray;
begin
Line := Self.FBmp.ScanLine[Y];
for i := 0 to Self.FBmp.Width - 1 do
Line[i] := Code;
end;


The obvious problem here is that I can't really call neither Self.FBmp.ScanLine[Y] nor Self.FBmp.Width because the compiler knows nothing about TBitmap or TMyBitmap at this point. Then I declared an interface and implemented it on TMyBitmap:



  IBitmap  = interface
['{029D42A0-132F-4C6E-BE72-648E1361C0A4}']
function GetWidth: Integer;
procedure SetWidth(Value: Integer);
function GetHeight: Integer;
procedure SetHeight(Value: Integer);
function GetScanLine(Y: Integer): Pointer;
property Width: Integer read GetWidth write SetWidth;
property Height: Integer read GetHeight write SetHeight;
property ScanLine[Y: Integer]: Pointer read GetScanLine;
end;

TMyBitmap = class (TSinglentonImplementation, IBitmap)
...
end;


Then I can add a type constraint on generic declaration to be able to call those methods through Self.FBmp from utility methods implementations.



TBmpUtility<T: IBitmap> = class


The problem here is: the standard TBitmap doesn't implement my IBitmap interface. So I can't use the utility class with a standard bitmap like follow:



Bmp := TBitmap.Create();
BmpUtil := TBmpUtility<TBitmap>.Create(Bmp);


I could do something like this:



TCustomBitmap = class (TBitmap, IBitmap)
...
end;


but the project code is using TBitmap everywhere, not TCustomBitmap so I can't interchange these types, so this is not an option.



I tried with a helper class. Something like these:



TBitmapHelper = class (IBitmap) helper for TBitmap
...
end;


but obviously, it doesn't work



Any idea how to fix this situation? Remember the goal from the beginning: having only one implementation code block for utility methods to deal with both TBitmap and TMyBitmap. If generics are the right solution, it should look like this:



Bmp := TBitmap.Create();
BmpUtil := TBmpUtility<TBitmap>.Create(Bmp);
BmpUtil.Fill(10, 0);
//or
MyBmp := TMyBitmap.Create();
BmpUtil := TBmpUtility<TMyBitmap>.Create(MyBmp);
BmpUtil.Fill(10, 0);


(FYI: I am using Delphi 10.2.3 [Tokyo])










share|improve this question




















  • 1





    I don't think generics are useful here. You need to create an adapter class that implements the interface by forwarding calls to the TBitmap instance.

    – David Heffernan
    Nov 25 '18 at 2:53






  • 1





    Related: Invoke method on generic type?

    – Remy Lebeau
    Nov 25 '18 at 6:41
















2















I am maintaining and extending a legacy app which works with 8bits bitmaps but for several reasons I did my own bitmap class from scratch (TMyBitmap) implementing some obvious features like Width, Height and ScanLine properties. Be aware that there is no relation between TBitmap and TMyBitmap (TMyBitmap doesn't inherited from TBitmap).



Now I want to do an utility class with several methods to work with either a standard TBitmap or my own TMyBitmap. The implementation of those methods is the same for a TBitmap or a TMyBitmap as they use only the "common" properties (Width, Height and ScanLine) so the generics looks like a suitable solution:



TBmpUtility<T> = class
strict private
FBmp: T;
public
constructor Create(Bmp: T);
procedure Fill(Y: Integer; Code: Byte); //example of an utility method
end;

procedure TBmpUtility<T>.Fill(Y: Integer; Code: Byte);
var
i: Integer;
Line: PByteArray;
begin
Line := Self.FBmp.ScanLine[Y];
for i := 0 to Self.FBmp.Width - 1 do
Line[i] := Code;
end;


The obvious problem here is that I can't really call neither Self.FBmp.ScanLine[Y] nor Self.FBmp.Width because the compiler knows nothing about TBitmap or TMyBitmap at this point. Then I declared an interface and implemented it on TMyBitmap:



  IBitmap  = interface
['{029D42A0-132F-4C6E-BE72-648E1361C0A4}']
function GetWidth: Integer;
procedure SetWidth(Value: Integer);
function GetHeight: Integer;
procedure SetHeight(Value: Integer);
function GetScanLine(Y: Integer): Pointer;
property Width: Integer read GetWidth write SetWidth;
property Height: Integer read GetHeight write SetHeight;
property ScanLine[Y: Integer]: Pointer read GetScanLine;
end;

TMyBitmap = class (TSinglentonImplementation, IBitmap)
...
end;


Then I can add a type constraint on generic declaration to be able to call those methods through Self.FBmp from utility methods implementations.



TBmpUtility<T: IBitmap> = class


The problem here is: the standard TBitmap doesn't implement my IBitmap interface. So I can't use the utility class with a standard bitmap like follow:



Bmp := TBitmap.Create();
BmpUtil := TBmpUtility<TBitmap>.Create(Bmp);


I could do something like this:



TCustomBitmap = class (TBitmap, IBitmap)
...
end;


but the project code is using TBitmap everywhere, not TCustomBitmap so I can't interchange these types, so this is not an option.



I tried with a helper class. Something like these:



TBitmapHelper = class (IBitmap) helper for TBitmap
...
end;


but obviously, it doesn't work



Any idea how to fix this situation? Remember the goal from the beginning: having only one implementation code block for utility methods to deal with both TBitmap and TMyBitmap. If generics are the right solution, it should look like this:



Bmp := TBitmap.Create();
BmpUtil := TBmpUtility<TBitmap>.Create(Bmp);
BmpUtil.Fill(10, 0);
//or
MyBmp := TMyBitmap.Create();
BmpUtil := TBmpUtility<TMyBitmap>.Create(MyBmp);
BmpUtil.Fill(10, 0);


(FYI: I am using Delphi 10.2.3 [Tokyo])










share|improve this question




















  • 1





    I don't think generics are useful here. You need to create an adapter class that implements the interface by forwarding calls to the TBitmap instance.

    – David Heffernan
    Nov 25 '18 at 2:53






  • 1





    Related: Invoke method on generic type?

    – Remy Lebeau
    Nov 25 '18 at 6:41














2












2








2








I am maintaining and extending a legacy app which works with 8bits bitmaps but for several reasons I did my own bitmap class from scratch (TMyBitmap) implementing some obvious features like Width, Height and ScanLine properties. Be aware that there is no relation between TBitmap and TMyBitmap (TMyBitmap doesn't inherited from TBitmap).



Now I want to do an utility class with several methods to work with either a standard TBitmap or my own TMyBitmap. The implementation of those methods is the same for a TBitmap or a TMyBitmap as they use only the "common" properties (Width, Height and ScanLine) so the generics looks like a suitable solution:



TBmpUtility<T> = class
strict private
FBmp: T;
public
constructor Create(Bmp: T);
procedure Fill(Y: Integer; Code: Byte); //example of an utility method
end;

procedure TBmpUtility<T>.Fill(Y: Integer; Code: Byte);
var
i: Integer;
Line: PByteArray;
begin
Line := Self.FBmp.ScanLine[Y];
for i := 0 to Self.FBmp.Width - 1 do
Line[i] := Code;
end;


The obvious problem here is that I can't really call neither Self.FBmp.ScanLine[Y] nor Self.FBmp.Width because the compiler knows nothing about TBitmap or TMyBitmap at this point. Then I declared an interface and implemented it on TMyBitmap:



  IBitmap  = interface
['{029D42A0-132F-4C6E-BE72-648E1361C0A4}']
function GetWidth: Integer;
procedure SetWidth(Value: Integer);
function GetHeight: Integer;
procedure SetHeight(Value: Integer);
function GetScanLine(Y: Integer): Pointer;
property Width: Integer read GetWidth write SetWidth;
property Height: Integer read GetHeight write SetHeight;
property ScanLine[Y: Integer]: Pointer read GetScanLine;
end;

TMyBitmap = class (TSinglentonImplementation, IBitmap)
...
end;


Then I can add a type constraint on generic declaration to be able to call those methods through Self.FBmp from utility methods implementations.



TBmpUtility<T: IBitmap> = class


The problem here is: the standard TBitmap doesn't implement my IBitmap interface. So I can't use the utility class with a standard bitmap like follow:



Bmp := TBitmap.Create();
BmpUtil := TBmpUtility<TBitmap>.Create(Bmp);


I could do something like this:



TCustomBitmap = class (TBitmap, IBitmap)
...
end;


but the project code is using TBitmap everywhere, not TCustomBitmap so I can't interchange these types, so this is not an option.



I tried with a helper class. Something like these:



TBitmapHelper = class (IBitmap) helper for TBitmap
...
end;


but obviously, it doesn't work



Any idea how to fix this situation? Remember the goal from the beginning: having only one implementation code block for utility methods to deal with both TBitmap and TMyBitmap. If generics are the right solution, it should look like this:



Bmp := TBitmap.Create();
BmpUtil := TBmpUtility<TBitmap>.Create(Bmp);
BmpUtil.Fill(10, 0);
//or
MyBmp := TMyBitmap.Create();
BmpUtil := TBmpUtility<TMyBitmap>.Create(MyBmp);
BmpUtil.Fill(10, 0);


(FYI: I am using Delphi 10.2.3 [Tokyo])










share|improve this question
















I am maintaining and extending a legacy app which works with 8bits bitmaps but for several reasons I did my own bitmap class from scratch (TMyBitmap) implementing some obvious features like Width, Height and ScanLine properties. Be aware that there is no relation between TBitmap and TMyBitmap (TMyBitmap doesn't inherited from TBitmap).



Now I want to do an utility class with several methods to work with either a standard TBitmap or my own TMyBitmap. The implementation of those methods is the same for a TBitmap or a TMyBitmap as they use only the "common" properties (Width, Height and ScanLine) so the generics looks like a suitable solution:



TBmpUtility<T> = class
strict private
FBmp: T;
public
constructor Create(Bmp: T);
procedure Fill(Y: Integer; Code: Byte); //example of an utility method
end;

procedure TBmpUtility<T>.Fill(Y: Integer; Code: Byte);
var
i: Integer;
Line: PByteArray;
begin
Line := Self.FBmp.ScanLine[Y];
for i := 0 to Self.FBmp.Width - 1 do
Line[i] := Code;
end;


The obvious problem here is that I can't really call neither Self.FBmp.ScanLine[Y] nor Self.FBmp.Width because the compiler knows nothing about TBitmap or TMyBitmap at this point. Then I declared an interface and implemented it on TMyBitmap:



  IBitmap  = interface
['{029D42A0-132F-4C6E-BE72-648E1361C0A4}']
function GetWidth: Integer;
procedure SetWidth(Value: Integer);
function GetHeight: Integer;
procedure SetHeight(Value: Integer);
function GetScanLine(Y: Integer): Pointer;
property Width: Integer read GetWidth write SetWidth;
property Height: Integer read GetHeight write SetHeight;
property ScanLine[Y: Integer]: Pointer read GetScanLine;
end;

TMyBitmap = class (TSinglentonImplementation, IBitmap)
...
end;


Then I can add a type constraint on generic declaration to be able to call those methods through Self.FBmp from utility methods implementations.



TBmpUtility<T: IBitmap> = class


The problem here is: the standard TBitmap doesn't implement my IBitmap interface. So I can't use the utility class with a standard bitmap like follow:



Bmp := TBitmap.Create();
BmpUtil := TBmpUtility<TBitmap>.Create(Bmp);


I could do something like this:



TCustomBitmap = class (TBitmap, IBitmap)
...
end;


but the project code is using TBitmap everywhere, not TCustomBitmap so I can't interchange these types, so this is not an option.



I tried with a helper class. Something like these:



TBitmapHelper = class (IBitmap) helper for TBitmap
...
end;


but obviously, it doesn't work



Any idea how to fix this situation? Remember the goal from the beginning: having only one implementation code block for utility methods to deal with both TBitmap and TMyBitmap. If generics are the right solution, it should look like this:



Bmp := TBitmap.Create();
BmpUtil := TBmpUtility<TBitmap>.Create(Bmp);
BmpUtil.Fill(10, 0);
//or
MyBmp := TMyBitmap.Create();
BmpUtil := TBmpUtility<TMyBitmap>.Create(MyBmp);
BmpUtil.Fill(10, 0);


(FYI: I am using Delphi 10.2.3 [Tokyo])







delphi






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 24 '18 at 23:41







Delmo

















asked Nov 24 '18 at 23:22









DelmoDelmo

1,17711121




1,17711121








  • 1





    I don't think generics are useful here. You need to create an adapter class that implements the interface by forwarding calls to the TBitmap instance.

    – David Heffernan
    Nov 25 '18 at 2:53






  • 1





    Related: Invoke method on generic type?

    – Remy Lebeau
    Nov 25 '18 at 6:41














  • 1





    I don't think generics are useful here. You need to create an adapter class that implements the interface by forwarding calls to the TBitmap instance.

    – David Heffernan
    Nov 25 '18 at 2:53






  • 1





    Related: Invoke method on generic type?

    – Remy Lebeau
    Nov 25 '18 at 6:41








1




1





I don't think generics are useful here. You need to create an adapter class that implements the interface by forwarding calls to the TBitmap instance.

– David Heffernan
Nov 25 '18 at 2:53





I don't think generics are useful here. You need to create an adapter class that implements the interface by forwarding calls to the TBitmap instance.

– David Heffernan
Nov 25 '18 at 2:53




1




1





Related: Invoke method on generic type?

– Remy Lebeau
Nov 25 '18 at 6:41





Related: Invoke method on generic type?

– Remy Lebeau
Nov 25 '18 at 6:41












1 Answer
1






active

oldest

votes


















3














As David suggested, you could make an adapter class. This class could implement your interface and act (in most cases) as a simple passthrough to the actual bitmap class. The one for TBitmap could look like this (some methods left out for brevity):



type
TBitmapAdapter = class(TInterfacedObject, IBitmap)
private
FBitmap: TBitmap;
function GetWidth: Integer;
procedure SetWidth(Value: Integer);
// And everything else from IBitmap
public
constructor Create(ABitmap: TBitmap);
end;

function TBitmapAdapter.GetWidth: Integer;
begin
Result := FBitmap.Width;
end;

procedure TBitmapAdapter.SetWidth(Value: Integer);
begin
FBitmap.Width := Value;
end;


You could make a single class that handles both types, but that would require ifs in each of the methods. I would make two separate classes, so you can simply create a TBitmapAdapter or a TMyBitmapAdapter.



You can simply construct that class and pass it around as interface. If your TBmpUtility would accept an IBitmap, you can construct it like this:



TBmpUtility.Create(TBitmapAdapter.Create(Self))


You could indeed write class helpers for TBitmap and TMyBitmap to create the right wrapper for you. Again the TBitmap version:



type
TBitmapHelper = class helper for TBitmap
function AsIBitmap: IBitmap;
end;

function TBitmapHelper.AsIBitmap: IBitmap;
begin
Result := TBitmapAdapter.Create(Self);
end;


You can then simply use it like this:



TBmpUtility.Create(Bitmap.AsIBitmap)


Or maybe just pass it to the methods of the utility class, you can have one utility instance which can handle any bitmap:



BmpUtility.Fill(Bitmap.AsIBitmap);


The reference to IBitmap can be stored temporarily to prevent the adapter being created and destroyed on each call:



var b: IBitmap;
begin
b := Bitmap.AsIBitmap;
BmpUtility.SetHeight(b, 100);
BmpUtility.SetWidth(b, 100);
BmpUtility.Fill(b);
end;


The result of Bitmap.AsIBitmap is the IBitmap interface of the adapter class, but the code that uses it won't even know, and the interface is refcounted, so the adapter will be freed as soon as it goes out of scope.






share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53463253%2fhow-to-use-a-generic-with-two-different-classes-but-one-of-them-from-the-vcl%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    3














    As David suggested, you could make an adapter class. This class could implement your interface and act (in most cases) as a simple passthrough to the actual bitmap class. The one for TBitmap could look like this (some methods left out for brevity):



    type
    TBitmapAdapter = class(TInterfacedObject, IBitmap)
    private
    FBitmap: TBitmap;
    function GetWidth: Integer;
    procedure SetWidth(Value: Integer);
    // And everything else from IBitmap
    public
    constructor Create(ABitmap: TBitmap);
    end;

    function TBitmapAdapter.GetWidth: Integer;
    begin
    Result := FBitmap.Width;
    end;

    procedure TBitmapAdapter.SetWidth(Value: Integer);
    begin
    FBitmap.Width := Value;
    end;


    You could make a single class that handles both types, but that would require ifs in each of the methods. I would make two separate classes, so you can simply create a TBitmapAdapter or a TMyBitmapAdapter.



    You can simply construct that class and pass it around as interface. If your TBmpUtility would accept an IBitmap, you can construct it like this:



    TBmpUtility.Create(TBitmapAdapter.Create(Self))


    You could indeed write class helpers for TBitmap and TMyBitmap to create the right wrapper for you. Again the TBitmap version:



    type
    TBitmapHelper = class helper for TBitmap
    function AsIBitmap: IBitmap;
    end;

    function TBitmapHelper.AsIBitmap: IBitmap;
    begin
    Result := TBitmapAdapter.Create(Self);
    end;


    You can then simply use it like this:



    TBmpUtility.Create(Bitmap.AsIBitmap)


    Or maybe just pass it to the methods of the utility class, you can have one utility instance which can handle any bitmap:



    BmpUtility.Fill(Bitmap.AsIBitmap);


    The reference to IBitmap can be stored temporarily to prevent the adapter being created and destroyed on each call:



    var b: IBitmap;
    begin
    b := Bitmap.AsIBitmap;
    BmpUtility.SetHeight(b, 100);
    BmpUtility.SetWidth(b, 100);
    BmpUtility.Fill(b);
    end;


    The result of Bitmap.AsIBitmap is the IBitmap interface of the adapter class, but the code that uses it won't even know, and the interface is refcounted, so the adapter will be freed as soon as it goes out of scope.






    share|improve this answer






























      3














      As David suggested, you could make an adapter class. This class could implement your interface and act (in most cases) as a simple passthrough to the actual bitmap class. The one for TBitmap could look like this (some methods left out for brevity):



      type
      TBitmapAdapter = class(TInterfacedObject, IBitmap)
      private
      FBitmap: TBitmap;
      function GetWidth: Integer;
      procedure SetWidth(Value: Integer);
      // And everything else from IBitmap
      public
      constructor Create(ABitmap: TBitmap);
      end;

      function TBitmapAdapter.GetWidth: Integer;
      begin
      Result := FBitmap.Width;
      end;

      procedure TBitmapAdapter.SetWidth(Value: Integer);
      begin
      FBitmap.Width := Value;
      end;


      You could make a single class that handles both types, but that would require ifs in each of the methods. I would make two separate classes, so you can simply create a TBitmapAdapter or a TMyBitmapAdapter.



      You can simply construct that class and pass it around as interface. If your TBmpUtility would accept an IBitmap, you can construct it like this:



      TBmpUtility.Create(TBitmapAdapter.Create(Self))


      You could indeed write class helpers for TBitmap and TMyBitmap to create the right wrapper for you. Again the TBitmap version:



      type
      TBitmapHelper = class helper for TBitmap
      function AsIBitmap: IBitmap;
      end;

      function TBitmapHelper.AsIBitmap: IBitmap;
      begin
      Result := TBitmapAdapter.Create(Self);
      end;


      You can then simply use it like this:



      TBmpUtility.Create(Bitmap.AsIBitmap)


      Or maybe just pass it to the methods of the utility class, you can have one utility instance which can handle any bitmap:



      BmpUtility.Fill(Bitmap.AsIBitmap);


      The reference to IBitmap can be stored temporarily to prevent the adapter being created and destroyed on each call:



      var b: IBitmap;
      begin
      b := Bitmap.AsIBitmap;
      BmpUtility.SetHeight(b, 100);
      BmpUtility.SetWidth(b, 100);
      BmpUtility.Fill(b);
      end;


      The result of Bitmap.AsIBitmap is the IBitmap interface of the adapter class, but the code that uses it won't even know, and the interface is refcounted, so the adapter will be freed as soon as it goes out of scope.






      share|improve this answer




























        3












        3








        3







        As David suggested, you could make an adapter class. This class could implement your interface and act (in most cases) as a simple passthrough to the actual bitmap class. The one for TBitmap could look like this (some methods left out for brevity):



        type
        TBitmapAdapter = class(TInterfacedObject, IBitmap)
        private
        FBitmap: TBitmap;
        function GetWidth: Integer;
        procedure SetWidth(Value: Integer);
        // And everything else from IBitmap
        public
        constructor Create(ABitmap: TBitmap);
        end;

        function TBitmapAdapter.GetWidth: Integer;
        begin
        Result := FBitmap.Width;
        end;

        procedure TBitmapAdapter.SetWidth(Value: Integer);
        begin
        FBitmap.Width := Value;
        end;


        You could make a single class that handles both types, but that would require ifs in each of the methods. I would make two separate classes, so you can simply create a TBitmapAdapter or a TMyBitmapAdapter.



        You can simply construct that class and pass it around as interface. If your TBmpUtility would accept an IBitmap, you can construct it like this:



        TBmpUtility.Create(TBitmapAdapter.Create(Self))


        You could indeed write class helpers for TBitmap and TMyBitmap to create the right wrapper for you. Again the TBitmap version:



        type
        TBitmapHelper = class helper for TBitmap
        function AsIBitmap: IBitmap;
        end;

        function TBitmapHelper.AsIBitmap: IBitmap;
        begin
        Result := TBitmapAdapter.Create(Self);
        end;


        You can then simply use it like this:



        TBmpUtility.Create(Bitmap.AsIBitmap)


        Or maybe just pass it to the methods of the utility class, you can have one utility instance which can handle any bitmap:



        BmpUtility.Fill(Bitmap.AsIBitmap);


        The reference to IBitmap can be stored temporarily to prevent the adapter being created and destroyed on each call:



        var b: IBitmap;
        begin
        b := Bitmap.AsIBitmap;
        BmpUtility.SetHeight(b, 100);
        BmpUtility.SetWidth(b, 100);
        BmpUtility.Fill(b);
        end;


        The result of Bitmap.AsIBitmap is the IBitmap interface of the adapter class, but the code that uses it won't even know, and the interface is refcounted, so the adapter will be freed as soon as it goes out of scope.






        share|improve this answer















        As David suggested, you could make an adapter class. This class could implement your interface and act (in most cases) as a simple passthrough to the actual bitmap class. The one for TBitmap could look like this (some methods left out for brevity):



        type
        TBitmapAdapter = class(TInterfacedObject, IBitmap)
        private
        FBitmap: TBitmap;
        function GetWidth: Integer;
        procedure SetWidth(Value: Integer);
        // And everything else from IBitmap
        public
        constructor Create(ABitmap: TBitmap);
        end;

        function TBitmapAdapter.GetWidth: Integer;
        begin
        Result := FBitmap.Width;
        end;

        procedure TBitmapAdapter.SetWidth(Value: Integer);
        begin
        FBitmap.Width := Value;
        end;


        You could make a single class that handles both types, but that would require ifs in each of the methods. I would make two separate classes, so you can simply create a TBitmapAdapter or a TMyBitmapAdapter.



        You can simply construct that class and pass it around as interface. If your TBmpUtility would accept an IBitmap, you can construct it like this:



        TBmpUtility.Create(TBitmapAdapter.Create(Self))


        You could indeed write class helpers for TBitmap and TMyBitmap to create the right wrapper for you. Again the TBitmap version:



        type
        TBitmapHelper = class helper for TBitmap
        function AsIBitmap: IBitmap;
        end;

        function TBitmapHelper.AsIBitmap: IBitmap;
        begin
        Result := TBitmapAdapter.Create(Self);
        end;


        You can then simply use it like this:



        TBmpUtility.Create(Bitmap.AsIBitmap)


        Or maybe just pass it to the methods of the utility class, you can have one utility instance which can handle any bitmap:



        BmpUtility.Fill(Bitmap.AsIBitmap);


        The reference to IBitmap can be stored temporarily to prevent the adapter being created and destroyed on each call:



        var b: IBitmap;
        begin
        b := Bitmap.AsIBitmap;
        BmpUtility.SetHeight(b, 100);
        BmpUtility.SetWidth(b, 100);
        BmpUtility.Fill(b);
        end;


        The result of Bitmap.AsIBitmap is the IBitmap interface of the adapter class, but the code that uses it won't even know, and the interface is refcounted, so the adapter will be freed as soon as it goes out of scope.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 25 '18 at 14:53

























        answered Nov 25 '18 at 13:57









        GolezTrolGolezTrol

        99.1k10133176




        99.1k10133176
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53463253%2fhow-to-use-a-generic-with-two-different-classes-but-one-of-them-from-the-vcl%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Tonle Sap (See)

            I get strange results when I access the Sqlitedatabase with Unity C# via XAMPP

            Guatemaltekische Davis-Cup-Mannschaft