Delphi издевается с обнуляемыми типами
Каков наилучший способ настройки макетов Delphi DSharp с типами Nullable из среды Spring? Я пробовал разные подходы и знаю, что, возможно, мне не хватает чего-то действительно элементарного, но я просто не могу понять, как заставить работать следующий код:
program DSharkMockNullable;
{$APPTYPE CONSOLE}
{$R *.res}
uses
DSharp.Testing.Mock,
Spring,
System.SysUtils;
type
{$M+}
IBaseMock = interface
['{B3311345-3C1F-47E3-8235-57B1BA04E957}']
function GetId: TNullableInteger;
procedure SetId(Value: TNullableInteger);
property Id: TNullableInteger read GetId write SetId;
end;
{$M+}
IMockMe = interface(IBaseMock)
['{07F8F233-E8F5-4743-88C5-97A66BB01E29}']
function GetObjectId: TNullableInteger;
procedure SetObjectId(Value: TNullableInteger);
property ObjectId: TNullableInteger read GetObjectId write SetObjectId;
function GetObjectName: TNullableString;
procedure SetObjectName(Value: TNullableString);
property ObjectName: TNullableString read GetObjectName write SetObjectName;
end;
TMyObject = class
public
function ObjectIdAsString(const AObject: IMockMe): string;
end;
{ TMyObject }
function TMyObject.ObjectIdAsString(const AObject: IMockMe): string;
var
LId: Integer;
LObjectId: Integer;
LObjectName: string;
begin
LId := AObject.Id; // ***** FAILS HERE with an "Invalid Typecast" error
LObjectId := AObject.ObjectId;
LObjectName := AObject.ObjectName;
Result := Format('Id: %d', [LId]);
Result := Format('Object Id: %d', [LObjectId]);
Result := Format('Object Name: %s', [LObjectName]);
end;
var
LMock: Mock<IMockMe>;
LObject: TMyObject;
begin
try
LMock.Setup.WillReturn(123).Any.WhenCalling.Id;
LMock.Setup.WillReturn(456).Any.WhenCalling.ObjectId;
LMock.Setup.WillReturn('blahblah').Any.WhenCalling.ObjectName;
LObject := TMyObject.Create;
Writeln(LObject.ObjectIdAsString(LMock.Instance));
LObject.Free;
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Любые идеи или предложения будут хорошими? Я использую Delphi XE5. Благодарю. Рик.
2 ответа
Правильный код должен выглядеть следующим образом (без использования вывода типов):
LMock.Setup.WillReturn<TNullableInteger>(123).Any.WhenCalling.Id;
LMock.Setup.WillReturn<TNullableInteger>(456).Any.WhenCalling.ObjectId;
LMock.Setup.WillReturn<TNullableString>('blahblah').Any.WhenCalling.ObjectName;
В дополнение к правильному ответу, который Рик уже дал здесь некоторое объяснение, почему это так:
Исходный код использует вывод типа для значений, переданных WillReturn, и выводит их как ShortInt
, SmallInt
(компилятор использует наименьший подходящий порядковый тип со знаком) и string
, Они хранятся как TValue
и возвращается при вызове метода. Но тогда RTTI пытается разыграть TValue
в тип возвращаемого значения и метод, который не удается, потому что он не знает, как привести ShortInt
или же SmallInt
к Nullable<Integer>
или string
к Nullable<string>
поскольку TValue.TryCast
не знает ни о каких неявных перегрузках операторов Nullable<>
введите и нет возможности зарегистрировать любые пользовательские конвертеры.
Хорошо, я должен был прочитать "DSharp for Dummies", но в любом случае, если у кого-то есть проблемы, вот ответ:
LMock.Setup.WillReturn<TNullableInteger>(123).Any.WhenCalling.Id;
LMock.Setup.WillReturn<TNullableInteger>(456).Any.WhenCalling.ObjectId;
LMock.Setup.WillReturn<TNullableString>('blahblah').Any.WhenCalling.ObjectName;
Я надеюсь, что это помогает кому-то еще там;-)