Skip to content

Instantly share code, notes, and snippets.

@jpluimers
Last active September 8, 2017 08:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpluimers/6a3b9eadf96aa6db7958d11a7091b925 to your computer and use it in GitHub Desktop.
Save jpluimers/6a3b9eadf96aa6db7958d11a7091b925 to your computer and use it in GitHub Desktop.
Delphi errors E2035 and E2250 when using overloaded methods on interfaces, but fine with same overloaded methods on classes. Works fine in C#. Workaround thanks to Stefan Glienke. Different manifestations of https://quality.embarcadero.com/browse/RSP-13007 (November 2015), https://web.archive.org/web/20130518145943/http://qc.embarcadero.com/wc/q…
unit MethodReferencesFailOnInterfacesUnit;
interface
type
TAction<T> = reference to procedure(const Value: T);
TConstFunction<T, TResult> = reference to function(const Value: T): TResult;
TTarget = class(TInterfacedObject)
end;
IContainer<T: class> = interface(IInterface)
['{5A8A80D4-4BF9-48E9-98CB-936E7F44F43F}']
procedure Delete(const Value: T);
function FirstOrDefault(const Id: Integer): T; overload;
function FirstOrDefault(const Id: string): T; overload;
function FirstOrDefaultInteger(const Id: Integer): T;
function FirstOrDefaultString(const Id: string): T;
end;
TContainer<T: class> = class(TInterfacedObject, IContainer<T>)
procedure Delete(const Value: T);
function FirstOrDefault(const Id: Integer): T; overload;
function FirstOrDefault(const Id: string): T; overload;
function FirstOrDefaultInteger(const Id: Integer): T;
function FirstOrDefaultString(const Id: string): T;
end;
//////////////////////////////////////////////////////////////////////////////////////////////
TUsage = class
function Delete<T: class>(const Container: IContainer<T>): TAction<T>; overload;
function FirstOrDefault<T: class>(const Container: IContainer<T>): TConstFunction<Integer, T>; overload;
function FirstOrDefault<T: class>(const Container: IContainer<T>; const Id: string): TConstFunction<string, T>; overload;
function FirstOrDefaultInteger<T: class>(const Container: IContainer<T>): TConstFunction<Integer, T>;
function FirstOrDefaultString<T: class>(const Container: IContainer<T>; const Id: string): TConstFunction<string, T>;
procedure InternalAction<T: TInterfacedObject>(const Value: T; const Action: TAction<T>);
procedure InternalFunction<T: TInterfacedObject>(const Value: T; const ConstFunction: TConstFunction<Integer, T>);
procedure Run;
end;
implementation //////////////////////////////////////////////////////////////////////////////////////////////
procedure TContainer<T>.Delete(const Value: T);
begin
// NOP
end;
function TContainer<T>.FirstOrDefault(const Id: Integer): T;
begin
Result := nil;
end;
function TContainer<T>.FirstOrDefault(const Id: string): T;
begin
Result := nil;
end;
function TContainer<T>.FirstOrDefaultInteger(const Id: Integer): T;
begin
Result := nil;
end;
function TContainer<T>.FirstOrDefaultString(const Id: string): T;
begin
Result := nil;
end;
//////////////////////////////////////////////////////////////////////////////////////////////
function TUsage.Delete<T>(const Container: IContainer<T>): TAction<T>;
begin
Result := procedure(const Value: T)
begin
Container.Delete(Value);
end;
end;
function TUsage.FirstOrDefault<T>(const Container: IContainer<T>): TConstFunction<Integer, T>;
begin
Result := function(const Id: Integer): T
begin
Result := Container.FirstOrDefault(Id);
end;
end;
function TUsage.FirstOrDefault<T>(const Container: IContainer<T>; const Id: string): TConstFunction<string, T>;
begin
Result := function(const Id: string): T
begin
Result := Container.FirstOrDefault(Id);
end;
end;
function TUsage.FirstOrDefaultInteger<T>(const Container: IContainer<T>): TConstFunction<Integer, T>;
begin
Result := function(const Id: Integer): T
begin
Result := Container.FirstOrDefaultInteger(Id);
end;
end;
function TUsage.FirstOrDefaultString<T>(const Container: IContainer<T>; const Id: string): TConstFunction<string, T>;
begin
Result := function(const Id: string): T
begin
Result := Container.FirstOrDefault(Id);
end;
end;
procedure TUsage.InternalAction<T>(const Value: T; const Action: TAction<T>);
begin
// NOP
end;
procedure TUsage.InternalFunction<T>(const Value: T; const ConstFunction: TConstFunction<Integer, T>);
begin
// NOP
end;
procedure TUsage.Run;
var
LContainerInstance: TContainer<TTarget>;
LContainerInterface: IContainer<TTarget>;
LTarget: TTarget;
begin
LTarget := TTarget.Create();
LContainerInstance := TContainer<TTarget>.Create();
InternalAction<TTarget>(LTarget, LContainerInstance.Delete);
InternalFunction<TTarget>(LTarget, LContainerInstance.FirstOrDefaultInteger);
InternalFunction<TTarget>(LTarget, LContainerInstance.FirstOrDefault);
LContainerInterface := LContainerInstance;
// Workaround if you know the original class as per Scott van der Linden:
InternalAction<TTarget>(LTarget, (LContainerInterface as TContainer<TTarget>).Delete);
InternalFunction<TTarget>(LTarget, (LContainerInterface as TContainer<TTarget>).FirstOrDefaultInteger);
InternalFunction<TTarget>(LTarget, (LContainerInterface as TContainer<TTarget>).FirstOrDefault);
// Nicer workaround as per Stefan Glienke:
InternalAction<TTarget>(LTarget, procedure(const Value: TTarget) begin LContainerInterface.Delete(Value); end);
InternalFunction<TTarget>(LTarget, function(const Id: Integer): TTarget begin Result := LContainerInterface.FirstOrDefaultInteger(Id); end);
InternalFunction<TTarget>(LTarget, function(const Id: Integer): TTarget begin Result := LContainerInterface.FirstOrDefault(Id); end);
// Nicer workaround if you have many types like TTarget:
InternalAction<TTarget>(LTarget, Delete<TTarget>(LContainerInterface));
InternalFunction<TTarget>(LTarget, FirstOrDefaultInteger<TTarget>(LContainerInterface));
InternalFunction<TTarget>(LTarget, FirstOrDefault<TTarget>(LContainerInterface));
// Failure:
InternalAction<TTarget>(LTarget, LContainerInterface.Delete);
InternalFunction<TTarget>(LTarget, LContainerInterface.FirstOrDefaultInteger);
InternalFunction<TTarget>(LTarget, LContainerInterface.FirstOrDefault);
// Why these two errors on the above three lines?
//[dcc32 Error] UsageUnit.pas(146): E2035 Not enough actual parameters
//[dcc32 Error] UsageUnit.pas(147): E2035 Not enough actual parameters
//[dcc32 Error] UsageUnit.pas(148): E2250 There is no overloaded version of 'FirstOrDefault' that can be called with these arguments
end;
end. //////////////////////////////////////////////////////////////////////////////////////////////
using System;
namespace MethodReferencesSucceedOnInterfaces
{
// based on Delphi code in https://gist.github.com/jpluimers/6a3b9eadf96aa6db7958d11a7091b925
public class Target
{
}
public interface IContainer<T> where T : class
{
void Delete(T value);
T FirstOrDefault(int id);
T FirstOrDefault(string id);
T FirstOrDefaultInteger(int id);
T FirstOrDefaultString(string id);
}
public class Container<T> : IContainer<T> where T : class
{
public void Delete(T value)
{
}
public T FirstOrDefault(int id)
{
return null;
}
public T FirstOrDefault(string id)
{
return null;
}
public T FirstOrDefaultInteger(int id)
{
return null;
}
public T FirstOrDefaultString(string id)
{
return null;
}
}
public class Usage
{
private void InternalCallFunc<T>(T value, Func<int, T> function) where T : class
{
}
private void InternalCallAction<T>(T value, Action<T> action) where T : class
{
}
private void Run()
{
Target target = new Target();
Container<Target> containerInstance = new Container<Target>();
InternalCallAction<Target>(target, containerInstance.Delete);
InternalCallFunc<Target>(target, containerInstance.FirstOrDefaultInteger);
InternalCallFunc<Target>(target, containerInstance.FirstOrDefault);
IContainer<Target> containerInterface = containerInstance;
InternalCallAction<Target>(target, containerInterface.Delete);
InternalCallFunc<Target>(target, containerInterface.FirstOrDefaultInteger);
InternalCallFunc<Target>(target, containerInterface.FirstOrDefault);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment