我有以下LUT(查找表)检索伪pchar的显示名称(所有这些预定义的pchar都是整数,您知道)输入:
const
RT_MIN = DWORD(RT_CURSOR);
RT_MAX = DWORD(RT_MANIFEST);
ResourceTypes: array [RT_MIN..RT_MAX] of PChar = (
'Hardware-dependent cursor',
'Bitmap',
'Hardware-dependent icon',
'Menu',
'Dialog box',
'String-table entry',
'Font directory',
'Font',
'Accelerator table',
'Application-defined resource (raw data)',
'Message-table entry',
'Hardware-independent cursor',
nil, { unknown, reserved or not used }
'Hardware-independent icon',
nil, { unknown, reserved or not used }
'Version',
'Dialog Include',
nil, { unknown, reserved or not used }
'Plug and Play',
'VxD',
'Animated cursor',
'Animated icon',
'HTML resource',
'Side-by-Side Assembly Manifest'
);
将其重写为case
语句是否有任何优点/缺点?这样做有什么好处/坏处吗?
我认为使用数组是最快的方法。例如,如果您查询ResourceTypes[2]
,程序将首先查看ResourceTypes[2]
,对PChar进行解引用并输出以零结尾的字符串。如果编译器很聪明,它可以识别字符串是不可更改的,因此它可以将所有字符串直接放在数组中,这样您就可以节省一次解引用操作。(对于那些对它感兴趣的人,可以使用HxD等十六进制编辑器查看内存内容,以检查这是否正确)
另一个可能在未来发生的问题是:假设微软定义了一个新的资源类型,这是一个非常特殊的东西,所以它得到一个像$FFFF这样的大数字。如果您正在使用case of
,您可以简单地添加2行代码来添加这个新的资源类型。通过查找表(或LUT,这个缩写对我来说是新的),你会有一个问题,因为你需要创建一个大小为65535的数组,其内容99%只是nil
s。
我将通过创建一个函数来完成它:
function GetHumanFriendlyResourceTypeName(AResourceType: PChar): string;
begin
if not Is_IntResource(AResourceType) then
begin
result := AResourceType;
end
else
begin
case Integer(AResourceType) of
Integer(RT_CURSOR):
result := 'Hardware-dependent cursor';
Integer(RT_BITMAP):
result := 'Bitmap';
Integer(RT_ICON):
result := 'Hardware-dependent icon';
Integer(RT_MENU):
result := 'Menu';
Integer(RT_DIALOG):
result := 'Dialog box';
Integer(RT_STRING):
result := 'String-table entry';
Integer(RT_FONTDIR):
result := 'Font directory';
Integer(RT_FONT):
result := 'Font';
Integer(RT_ACCELERATOR):
result := 'Accelerator table';
Integer(RT_RCDATA):
result := 'Application-defined resource (raw data)';
Integer(RT_MESSAGETABLE):
result := 'Message-table entry';
Integer(RT_GROUP_CURSOR):
result := 'Hardware-independent cursor';
Integer(RT_GROUP_ICON):
result := 'Hardware-independent icon';
Integer(RT_VERSION):
result := 'Version';
Integer(RT_DLGINCLUDE):
result := 'Dialog Include';
Integer(RT_PLUGPLAY):
result := 'Plug and Play';
Integer(RT_VXD):
result := 'VxD';
Integer(RT_ANICURSOR):
result := 'Animated cursor';
Integer(RT_ANIICON):
result := 'Animated icon';
Integer(RT_HTML):
result := 'HTML resource';
Integer(RT_MANIFEST):
result := 'Side-by-Side Assembly Manifest';
else
result := Format('(Unknown type %d)', [Integer(AResourceType)]);
end;
end;
end;
下面是代码的演示:
procedure TForm1.Button1Click(Sender: TObject);
begin
// Hardware-dependent icon
ShowMessage(GetHumanFriendlyResourceTypeName(MAKEINTRESOURCE(3)));
// (Unknown type 123)
ShowMessage(GetHumanFriendlyResourceTypeName(MAKEINTRESOURCE(123)));
// AVI
ShowMessage(GetHumanFriendlyResourceTypeName(PChar('AVI')));
end;
性能没有您的解决方案那么高,但是这个函数有几个优点:
- 这个函数更容易阅读,因为每个
RT_
常数都站在它的人性化名称前面。因此,代码也更易于维护。在LUT中,人类友好的名称可能会被意外地交换(也因为每个人类友好的名称前面没有注释表示官方RT_
常量名称)。 - 如果标识符未知,该函数也会显示一个友好的字符串"(Unknown type 123)"。
- 如果字符串不是预定义类型(
RT_
),该函数也将取消对字符串的引用 - 使用这个函数,你可以通过将字符串静态地放入resourcestrings或通过查询翻译函数/stringlist来动态地国际化你的应用程序。