问题 泛型无法正确解析方法类型


考虑以下 :

{$APPTYPE CONSOLE}

uses
  Generics.Collections;

type
  TObjProc = procedure of object;
  TFoo = class
    public procedure DoFoo;
    public procedure DoBar;
  end;

procedure TFoo.DoFoo;
begin
  WriteLn('foo');
end;

procedure TFoo.DoBar;
begin
  WriteLn('bar');
end;

var
  ProcList : TList<TObjProc>;
  Foo : TFoo;
  aProc : TObjProc;
begin
  Foo := TFoo.Create;
  ProcList := TList<TObjProc>.Create;
  ProcList.Add(Foo.DoFoo);
  ProcList.Add(Foo.DoBar);
  for aProc in ProcList do aProc;
  ReadLn;
end.

这产生了预期的输出

foo
bar

现在假设我们要从列表中分配一个过程。枚举作品,如上所述。这也有效:

aProc := ProcList.Items[0];
aProc;

但这会引发编译器错误 :

aProc := ProcList.First;
// E2010 Incompatible types: 
//'procedure, untyped pointer or untyped parameter' and 'TObjProc'

这是多么奇怪的事

function TList<T>.First: T;
begin
  Result := Items[0];
end;

发生什么了?

这是否也会影响较新版本的Delphi?如果有一个合理的期望,这应该有效(我认为有),我很想QC。


968
2017-10-01 15:16


起源



答案:


这不是编译器错误,也不是这个问题与您使用泛型有关。都 First 和 Last 是函数,因此编译器无法判断您是要调用它们还是引用它们。要明确,让编译器知道你的意思是通过提供parens来调用该函数。

aProc := ProcList.First();
aProc := ProcList.Last();

然而,在调用过程和函数时,允许省略parens的决定再次让你感到困惑。这个设计决定虽然在制作时看起来如此吸引人,但由于程序类型在现代编码风格中被如此广泛地使用,因此看起来不那么重要。

当你写作 ProcList.First 编译器面临歧义。您是要调用该函数,还是希望将该函数称为过程类型?在许多情况下,编译器无法解决模糊性,但这不是这种情况,其中表达式位于赋值运算符的右侧。面对这种歧义,编译器假定您要引用该函数。

这需要这个选择,因为另一个选择会更糟。至少通过这种方式,您可以提供parens并明确指出您要调用的函数。如果编译器走向另一个方向,那么你将继续寻找一种方法来告诉它你想要引用该函数。

最后,如果 First 和 Last 已被实施为属性,没有歧义。


13
2017-10-01 15:22



来自C#,C,C ++,Python和所有其他语言。除了VB。当你发现自己处于一组二号而另一个成员是VB时,总是很糟糕! - David Heffernan
而且,AFAIK,Swift,那么它就变成了三个一组。 - Rudy Velthuis


答案:


这不是编译器错误,也不是这个问题与您使用泛型有关。都 First 和 Last 是函数,因此编译器无法判断您是要调用它们还是引用它们。要明确,让编译器知道你的意思是通过提供parens来调用该函数。

aProc := ProcList.First();
aProc := ProcList.Last();

然而,在调用过程和函数时,允许省略parens的决定再次让你感到困惑。这个设计决定虽然在制作时看起来如此吸引人,但由于程序类型在现代编码风格中被如此广泛地使用,因此看起来不那么重要。

当你写作 ProcList.First 编译器面临歧义。您是要调用该函数,还是希望将该函数称为过程类型?在许多情况下,编译器无法解决模糊性,但这不是这种情况,其中表达式位于赋值运算符的右侧。面对这种歧义,编译器假定您要引用该函数。

这需要这个选择,因为另一个选择会更糟。至少通过这种方式,您可以提供parens并明确指出您要调用的函数。如果编译器走向另一个方向,那么你将继续寻找一种方法来告诉它你想要引用该函数。

最后,如果 First 和 Last 已被实施为属性,没有歧义。


13
2017-10-01 15:22



来自C#,C,C ++,Python和所有其他语言。除了VB。当你发现自己处于一组二号而另一个成员是VB时,总是很糟糕! - David Heffernan
而且,AFAIK,Swift,那么它就变成了三个一组。 - Rudy Velthuis