Why can't I assign my function reference to a matching variable? E2555 is raised

后端 未结 3 1297
情深已故
情深已故 2021-01-01 20:49

I\'m trying to build an custom comparer which allows the assignment of the comparison function to an internal field. In order to ease the creation of the comparer, I tried t

3条回答
  •  一向
    一向 (楼主)
    2021-01-01 21:13

    The compiler error on my English Delphi reads:

    [dcc32 Error] E2555 Cannot capture symbol 'Result'

    This is due to a defective design. There's no reason for any variable capture to be taking place here at all. The right hand side of the assignment is an instance method rather than an anonymous method. But the compiler handles that by wrapping the method in an anonymous method. The compiler translates

    Result.FVar := Result.CompareInternal;
    

    to

    Result.FVar := 
      function(const Arg1, Arg2: string): Integer
      begin
        InnerResult := OuterResult.CompareInternal(Arg1, Arg2);
      end;
    

    Leaving aside the confusion over the two separate result variables, the compiler rejects this because the outer result variable is not a local, it's a var parameter. And so cannot be captured.

    But the whole design is wrong in my view. There's no need for any variable capture. When you write Result.CompareInternal you intend to refer to a normal of object method. With a better design, the compiler would allow this assignment without creating an anonymous method.

    You can work around the problem like this:

    class function TDemo.Construct: TDemo;
    var
      Demo: TDemo;
    begin
      Demo := TDemo.Create();
      Demo.FVar := Demo.CompareInternal;
      Result := Demo;
    end;
    

    Here the local variable Demo can be captured.

    Or as I would suggest, like this:

    program ConsoleDemo1;
    
    {$APPTYPE CONSOLE}
    
    uses
      Generics.Defaults,
      System.SysUtils;
    
    type
      TConstFunc = reference to function(const Arg1: T1; 
        const Arg2: T2): TResult;
    
      TDemo = class(TComparer)
      private
        FVar: TConstFunc;
        function CompareInternal(const L, R: string): Integer;
      public
        constructor Create;
        function Compare(const L, R: string): Integer; override;
      end;
    
    constructor TDemo.Create;
    begin
      inherited;
      FVar := CompareInternal;
    end;
    
    function TDemo.Compare(const L, R: string): Integer;
    begin
      Result := FVar(L, R);
    end;
    
    function TDemo.CompareInternal(const L, R: string): Integer;
    begin
      Result := AnsiCompareStr(L, R);
    end;
    
    end.
    

提交回复
热议问题