如何设置和检查枚举的无值?
How to set and check for no-value as enumerate?
我正在将一些常用值转换为枚举值。但我对那些缺少 value/no-value 也有意义的问题有疑问:
vDataType:string;
If vDataType = '' Then // no datatype assigned, yet -> handle appropriately
else if vDataType = 'PROJECT' then // process as project record
else if vDataTpye = 'GROUP' then // process as project group record
else if vDataType = 'TASK' then // process as project task
如果我现在设置:
TDataType = (dtProject, dtGroup, dtTask);
var vDatatype:TDataType;
我可以用
If vDataType = dtProject Then ...
else if vDataType = dtGroup then ...
else if vDataType = dtTaks then ...
但由于第一个元素是 dtProject 为 0,我现在如何检查没有值,以替换:if vDatatype = '' then...
记录都在同一个数组中,因此无值有意义,因为它将记录与标记为项目、组或任务的其他记录区分开来。记录在导入记录的过程中被标记,我想避免将枚举值之一(如 dtNone)设置为不是 dtProject、dtGroup 或 dtTask 的所有记录。
编辑:
这里是我被卡住的例子:
TData = record
LineID:integer;
FullLine:string;
//...
DataType:string;
end;
var vArray:TArray<TData>;
procedure ProcessDataAfterImport;
var i:integer;
begin
for i:=0 to High(vArray) do
begin
if Copy(vArray[i].FullLine,1,4)='PRJ=' then
vArray[i].DataType := 'PROJECT'
else if Copy(vArray[i].FullLine,1,4)='GRP=' then
vArray[i].DataType := 'GROUP'
else if Copy(vArray[i].FullLine,1,4)='TSK=' then
vArray[i].DataType := 'TASK';
end;
end;
procedure ProcessProjects;
var i:integer;
begin
for i:=0 to High(vArray) do
if vArray[i].DataType = 'PROJECT' Then
ParseProjectRecord(vArray[i]);
end;
我有很多与基于数据类型处理记录的 ProcessProjects 类似的方法,我不想在任何地方使用 'PROJECT',而是使用枚举,它们是整数,我认为它也更快并且不容易出错 'PROJCET'。我数了一下 'PROJECT' 被使用了 55 次。 'GROUP' 和 'TASK' 少一点,但我还有其他示例使用类似的字符串值来指定记录类型。
您似乎要求的是不可能的。
很难说没有看到你的案例中涉及的更多代码,但我怀疑空字符串的使用——无论是无意还是有意——是在利用字符串是Delphi 声明为局部变量时由运行时初始化。这还包括 - 例如 - 接口引用和动态数组。
对局部变量的这些类型进行这种特殊处理是必要的,因为运行时以特殊方式处理这些类型,这些方式依赖于确定这些类型的变量处于有效的初始状态。
例如String
的 RTTI 中的 Length 字段必须 正确反映为保存该字符串中的字符而分配的内存,否则内存错误将修改该字符串时的结果。一个接口必须是 NIL 以避免在初始分配一些其他值时对 Release 的无效调用。等等等等
other 类型的值声明为 class 成员变量,例如,可能 出现 在新实例中初始化class 的结果,但这是对那些 classes 的新分配实例进行内存归零的结果,而不是任何实际初始化本身。
从 String
更改为枚举时的问题是枚举不需要(因此不接受)任何此类特殊处理,因此 必须 明确初始化。
注意: 即使枚举被自动初始化,它们也会被初始化为 0
(零),即枚举的第一个成员(除非第一个成员已明确分配了一个非零序数值)。
考虑到这一点,这意味着如果需要枚举变量能够指示 No Value
或 Not Set
,则此 必须 显示为枚举本身的有效值,您必须根据需要显式初始化该类型的变量。
注意: 如果您确保此 Not set
值是枚举的第一个成员,那么正如您所观察到的那样,它将具有值 0
(零)这意味着该类型的任何 class 成员变量将自动 "initialised" 在该 class.[=20= 的新实例中具有此 Not set
值]
但是对于 local 变量,record members 等,你必须明确地初始化它,就像你必须初始化一个Integer
或 Boolean
等等
在Delphi中,您可以设置枚举的值。例如你可以这样写:
TDataType = (dtNone=-1, dtProject, ...);
这可能会解决您将 0
分配给 dtNone
的问题。
但是,正如其他人所说,如果没有更多代码,很难看出这会导致什么结果。目前,尚不清楚枚举是否会代替字符串产生任何影响。
您可以使用
的潜在危险方法
If vDataType = dtProject Then ...
else if vDataType = dtGroup then ...
else if vDataType = dtTaks then ...
else // no predefined datatype assigned, yet -> handle appropriately
只要满足前一个 if 和 else if 条件的 none,就会执行最后的 else。
现在为什么这有潜在的危险?
正如 Deltics 在他的回答中已经解释的那样 局部变量、记录成员等 没有初始化为某些默认状态,而是只为它们分配了特定的内存位置,内存数据可能之前被分配给某物而存储在该位置的数据可能包含将转化为您的 set
值之一的数据,即使您没有分配它也是如此。
所以我仍然建议您定义默认设置值,并在每次分配其他 none 时分配它。
我正在将一些常用值转换为枚举值。但我对那些缺少 value/no-value 也有意义的问题有疑问:
vDataType:string;
If vDataType = '' Then // no datatype assigned, yet -> handle appropriately
else if vDataType = 'PROJECT' then // process as project record
else if vDataTpye = 'GROUP' then // process as project group record
else if vDataType = 'TASK' then // process as project task
如果我现在设置:
TDataType = (dtProject, dtGroup, dtTask);
var vDatatype:TDataType;
我可以用
If vDataType = dtProject Then ...
else if vDataType = dtGroup then ...
else if vDataType = dtTaks then ...
但由于第一个元素是 dtProject 为 0,我现在如何检查没有值,以替换:if vDatatype = '' then...
记录都在同一个数组中,因此无值有意义,因为它将记录与标记为项目、组或任务的其他记录区分开来。记录在导入记录的过程中被标记,我想避免将枚举值之一(如 dtNone)设置为不是 dtProject、dtGroup 或 dtTask 的所有记录。
编辑:
这里是我被卡住的例子:
TData = record
LineID:integer;
FullLine:string;
//...
DataType:string;
end;
var vArray:TArray<TData>;
procedure ProcessDataAfterImport;
var i:integer;
begin
for i:=0 to High(vArray) do
begin
if Copy(vArray[i].FullLine,1,4)='PRJ=' then
vArray[i].DataType := 'PROJECT'
else if Copy(vArray[i].FullLine,1,4)='GRP=' then
vArray[i].DataType := 'GROUP'
else if Copy(vArray[i].FullLine,1,4)='TSK=' then
vArray[i].DataType := 'TASK';
end;
end;
procedure ProcessProjects;
var i:integer;
begin
for i:=0 to High(vArray) do
if vArray[i].DataType = 'PROJECT' Then
ParseProjectRecord(vArray[i]);
end;
我有很多与基于数据类型处理记录的 ProcessProjects 类似的方法,我不想在任何地方使用 'PROJECT',而是使用枚举,它们是整数,我认为它也更快并且不容易出错 'PROJCET'。我数了一下 'PROJECT' 被使用了 55 次。 'GROUP' 和 'TASK' 少一点,但我还有其他示例使用类似的字符串值来指定记录类型。
您似乎要求的是不可能的。
很难说没有看到你的案例中涉及的更多代码,但我怀疑空字符串的使用——无论是无意还是有意——是在利用字符串是Delphi 声明为局部变量时由运行时初始化。这还包括 - 例如 - 接口引用和动态数组。
对局部变量的这些类型进行这种特殊处理是必要的,因为运行时以特殊方式处理这些类型,这些方式依赖于确定这些类型的变量处于有效的初始状态。
例如String
的 RTTI 中的 Length 字段必须 正确反映为保存该字符串中的字符而分配的内存,否则内存错误将修改该字符串时的结果。一个接口必须是 NIL 以避免在初始分配一些其他值时对 Release 的无效调用。等等等等
other 类型的值声明为 class 成员变量,例如,可能 出现 在新实例中初始化class 的结果,但这是对那些 classes 的新分配实例进行内存归零的结果,而不是任何实际初始化本身。
从 String
更改为枚举时的问题是枚举不需要(因此不接受)任何此类特殊处理,因此 必须 明确初始化。
注意: 即使枚举被自动初始化,它们也会被初始化为 0
(零),即枚举的第一个成员(除非第一个成员已明确分配了一个非零序数值)。
考虑到这一点,这意味着如果需要枚举变量能够指示 No Value
或 Not Set
,则此 必须 显示为枚举本身的有效值,您必须根据需要显式初始化该类型的变量。
注意: 如果您确保此 Not set
值是枚举的第一个成员,那么正如您所观察到的那样,它将具有值 0
(零)这意味着该类型的任何 class 成员变量将自动 "initialised" 在该 class.[=20= 的新实例中具有此 Not set
值]
但是对于 local 变量,record members 等,你必须明确地初始化它,就像你必须初始化一个Integer
或 Boolean
等等
在Delphi中,您可以设置枚举的值。例如你可以这样写:
TDataType = (dtNone=-1, dtProject, ...);
这可能会解决您将 0
分配给 dtNone
的问题。
但是,正如其他人所说,如果没有更多代码,很难看出这会导致什么结果。目前,尚不清楚枚举是否会代替字符串产生任何影响。
您可以使用
的潜在危险方法If vDataType = dtProject Then ...
else if vDataType = dtGroup then ...
else if vDataType = dtTaks then ...
else // no predefined datatype assigned, yet -> handle appropriately
只要满足前一个 if 和 else if 条件的 none,就会执行最后的 else。
现在为什么这有潜在的危险?
正如 Deltics 在他的回答中已经解释的那样 局部变量、记录成员等 没有初始化为某些默认状态,而是只为它们分配了特定的内存位置,内存数据可能之前被分配给某物而存储在该位置的数据可能包含将转化为您的 set
值之一的数据,即使您没有分配它也是如此。
所以我仍然建议您定义默认设置值,并在每次分配其他 none 时分配它。