Function delphi检查是否使用了函数结果值
我的问题和你的一样,只是语言不同。我正在使用Delphi 按照您将在Java中看到的链接,这似乎是不可能的,因此我假设这也适用于Delphi,但我不能完全确定 我想知道,函数是否可以检查调用过程/函数是否使用函数提供的返回值。 我尝试过这个方法,但没有成功:(我想如果存在一个解决方案,它的行为会与此类似) 检查似乎没有用,但我的函数生成了一个加密文件,解密此文件时需要返回值,因此最好通知用户,而不仅仅是生成一个无用的文件,因此我希望检查返回值的使用情况 可能的解决办法: 我有一个想法,但要么不知道这是否可行,要么不知道如何实现:该函数可以扫描被我的应用程序占用的RAM部分,并在命令Function delphi检查是否使用了函数结果值,function,delphi,return-value,Function,Delphi,Return Value,我的问题和你的一样,只是语言不同。我正在使用Delphi 按照您将在Java中看到的链接,这似乎是不可能的,因此我假设这也适用于Delphi,但我不能完全确定 我想知道,函数是否可以检查调用过程/函数是否使用函数提供的返回值。 我尝试过这个方法,但没有成功:(我想如果存在一个解决方案,它的行为会与此类似) 检查似乎没有用,但我的函数生成了一个加密文件,解密此文件时需要返回值,因此最好通知用户,而不仅仅是生成一个无用的文件,因此我希望检查返回值的使用情况 可能的解决办法: 我有一个想法,但要么不知
Result:='类似于F8975BE8AC0192#2983FE4A#B9DFE25'
触发后检查返回值(字符串)是否存在。字符串不太可能存在两次,这个简单的检查完全符合我的目的。
一般来说,这可能不起作用,因为结果可能存在两次,但在我的情况下,这是不可能的
为此,我扩展了我的原始问题:
如何在包含该函数的应用程序占用的RAM部分中搜索字符串,该应用程序希望检查该字符串?
据我所知,要检查外部应用程序的这一点要困难得多,这在这里是不需要的。所以我想你要问的是,你是否可以从一个函数返回两段数据,加密字符串和解密密钥。 您可以声明一个包含两个项的类并返回其实例,也可以将它们作为参数接口的一部分传递回去
procedure cruncher(incoming:string;var encrypted:string;var decryptkey:string)
就个人风格而言,我反对通过函数结果返回一半答案。在Delphi中,您试图做的是不可能的。这不是一个“语言问题”。但这也不是问题 你真的在背对背地考虑这个问题。我会尽力解释原因;希望你能放弃这愚蠢的行为 总结
- 函数只能做一件事。一个函数尝试做的事情越多:正确实现它就越困难,其他函数重用起来就越困难
- 任何你可能想到的黑客都可以轻易绕过。因此,您最终会遇到更复杂的问题和相同的非问题
- 确保调用方正确使用函数不是您的责任。这就是疯狂和不断成长的兔子窝
- 您应该只根据“合同”实现您的功能,正确使用它是调用方的责任。若调用者并没有正确地使用它,那个么调用者就有一个bug,直到调用代码被修复为止。就这么简单
只做一件事 当函数做不止一件事时,就不可能(不经过仔细的重构)使用一个特性而不使用另一个特性。该函数更难测试,因为:调用过程中更改的内容越多,需要进行的设置越多,需要检查的内容越多,可能需要考虑的排列也越多 Javascript问题中的情况甚至更糟,因为这两件事有根本的区别:
- 函数样式版本可以保证不改变状态
- 而另一种样式用于修改状态
S := HybridFunction(...);
if (S <> '') then S := '';
这里已经有问题了,因为你的函数显然在做两件事。将其拆分为2个函数,调用方也将更容易编写
function GetKey(): TKey;
procedure EncryptFile(AKey: TKey);
然后,调用方可以在尝试加密之前验证:
LKey := GetKey();
if Assigned(LKey) then
EncryptFile(LKey)
else { report the error as you choose }
这就是为什么我说你要背对背地讨论这个问题。我相信你的问题可能源于实现某种绝对防弹的东西的愿望,或者源于一种使事情变得比实际更困难的设计选择 防弹实施 如果您作为一名开发人员做得很好,那么函数命名和签名将向调用者指示预期用途。他是否理解这一点,并最终正确使用它,很可能超出你的控制,正如评论所指出的:你在哪里停下来?可能总会有办法挫败您的实现 可以而且应该做任何事情吗? 但是考虑到您问题的技术方面,以及无法检查是否使用函数结果完成了某些操作(因为函数代码已经存在),我的想法是使结果本身“更智能” 您提到您的加密密钥是一个字符串,您可以称之为“unique”。因此,可以使用Delphi的字符串引用计数(至少对于除
WideString
之外的字符串)来确保它仍然在某个地方被引用。与同样是引用计数的IInterfacedObject
相结合,TInterfaceObject
可以检查它是否比监视的字符串寿命长
接口
IRefCheck = interface
['{E6A54A33-E4DB-4486-935A-00549E6793AC}']
function Value: string;
end;
由TInterfacedObject实施
TRefCheck = class(TInterfacedObject, IRefCheck)
strict private
FString: string;
public
constructor Create(const S: string);
destructor Destroy; override;
function Value: string;
end;
constructor TRefCheck.Create(const S: string);
begin
FString := S;
end;
destructor TRefCheck.Destroy;
begin
Assert(StringRefCount(FString) > 1, 'Reference check failed for ' + FString);
inherited Destroy;
end;
function TRefCheck.Value: string;
begin
Result := FString;
end;
像 TRefCheck = class(TInterfacedObject, IRefCheck)
strict private
FString: string;
public
constructor Create(const S: string);
destructor Destroy; override;
function Value: string;
end;
constructor TRefCheck.Create(const S: string);
begin
FString := S;
end;
destructor TRefCheck.Destroy;
begin
Assert(StringRefCount(FString) > 1, 'Reference check failed for ' + FString);
inherited Destroy;
end;
function TRefCheck.Value: string;
begin
Result := FString;
end;
function GetEncryptedFileKey(Key: string): IRefCheck;
begin
Result := TRefCheck.Create(Key);
end;
procedure Test;
var
S: string;
begin
S := GetEncryptedFileKey('Test Value 1').Value;
GetEncryptedFileKey('Test Value 2');
end;
TRefCheckRec = record
private
RefCheck: IRefCheck;
function AsString: string;
public
class operator Implicit(Value: TRefCheckRec): string;
class function CreateNew(S: string): TRefCheckRec; static;
end;
function TRefCheckRec.AsString: string;
begin
RefCheck.Value;
end;
class function TRefCheckRec.CreateNew(S: string): TRefCheckRec;
begin
Result.RefCheck := TRefCheck.Create(S);
end;
class operator TRefCheckRec.Implicit(Value: TRefCheckRec): string;
begin
Result := Value.AsString;
end;
function GetEncryptedFileKey(Key: string): TRefCheckRec;
begin
Result := TRefCheckRec.CreateNew(Key);
end;
procedure Test2;
var
S: string;
begin
S := GetEncryptedFileKey('Test Value Record');
GetEncryptedFileKey('Test Value Record 2');
end;
function GetEncryptedFileKey: string;
procedure EncryptFile(var EncryptionKey: string);
TEncryptedFile = class
private
FEncryptionKey: string;
FKeyPersisted: Boolean;
public
constructor Create;
destructor Destroy; override;
function GetEncryptionKey: string;
procedure SaveEncryptionKeyToFile;
end;
constructor TEncryptedFile.Create;
begin
FKeyPersisted := False;
FEncryptionKey := ...
end;
destructor TEncryptedFile.Destroy;
begin
if not FKeyPersisted then
SaveEncryptionKeyToFile;
inherited Destroy;
end;
function TEncryptedFile.GetEncryptionKey: string;
begin
Result := FEncryptionKey;
FKeyPersisted := True;
end;
procedure TEncryptedFile.SaveEncryptionKeyToFile;
begin
FKeyPersisted := True;
// Save to file
...
end;
function CreateEncryptedFile: TEncryptedFile;
begin
Result := TEncryptedFile.Create;
end;