是否可以使用 IF 语句调整过程的参数?
Is it possible to adjust the Parameters of a procedure with an IF statement?
我有两个几乎相同的程序,唯一的区别是其中一个参数的数据类型。
procedure InsertNewStringAnswer(AidQuestion: Integer; AAnswer: String);
和
procedure InsertNewBoolAnswer(AidQuestion: Integer; AAnswer: Boolean);
我需要根据问题更改答案类型。我是否必须编写两个过程并用第三个过程调用它们,或者有什么方法可以在运行时更改参数 AAnswer 的数据类型?
我正在编辑它以展示我如何构建解决方案。在这种情况下,我使用了 Variant 类型。我无法验证这是否是最佳做法,但它有效:).
procedure InsertNewAnswer(AidQuestion: Integer; AAnswer: Variant);
var
idNextRecord: string;
isBoolean: Boolean;
StrAAnswer: String;
BoolAAnswer: Boolean;
begin
With Connection.queryMain Do
begin
SQL.Clear;
SQL.Text := 'select count(*) as summe from dbo.Answer';
Open;
end;
idNextRecord := Connection.queryMain.FieldByName('summe').Asstring;
With Connection.queryMain Do
begin
SQL.Clear;
//Here I check if the question has a boolean or string answer.
SQL.Text :=('select isBool from dbo.Questions AS ISBOOL WHERE idQuestion= :SQLAidQuestion;');
ParamByName('SQLAidQuestion').AsInteger := AidQuestion;
Prepare;
Open;
end;
//and write it to a Variable.
isBoolean := Connection.queryMain.FieldByName('isBool').AsBoolean;
Connection.queryMain.SQL.Clear;
//I then use a if statement to change the Variant Type accordingly
if isBoolean = True then
begin
//Note that System.Variants does not have VarToBool so I use a workaround
BoolAAnswer := StrToBool(VarToStr(AAnswer));
AAnswer := BoolAAnswer;
Connection.queryMain.SQL.Text :=
('INSERT INTO Frueherkennung.dbo.Answer' +
'(idAnswer, idQuestion, Answer)VALUES(' + idNextRecord +
', :sqlQuestion, :sqlAAnswer);');
Connection.queryMain.ParamByName('sqlQuestion').AsInteger := AidQuestion;
Connection.queryMain.ParamByName('sqlAAnswer').AsBoolean := AAnswer;
end
else
begin
StrAAnswer := VarToStr(AAnswer);
MessageDlg('iSBool:= False', mtError, [mbok], 0);
AAnswer := StrAAnswer;
Connection.queryMain.SQL.Text :=('INSERT INTO Frueherkennung.dbo.Answer' +
'(idAnswer, idQuestion, Answer)VALUES(' + idNextRecord +
', :sqlQuestion, :sqlAAnswer);');
Connection.queryMain.ParamByName('sqlQuestion').AsInteger := AidQuestion;
Connection.queryMain.ParamByName('sqlAAnswer').Asstring := AAnswer
end;
With Connection.queryMain Do
begin
Prepare;
Execute;
SQL.Clear;
end;
end;
谢谢大家的精彩回答。
如果 AAnswer 参数是允许其中几乎所有内容的变体类型,则您可以编写单个函数。
您也可以使用重载关键字保留两个同名的过程。
您还可以让一个过程将 AAnswer 作为指向调用者想要使用的存储的无类型指针。当然在那个时候,问题必须包含必要的信息来决定点是指向布尔值还是指向字符串。
最后这个选项真的不推荐。对我来说,最干净的解决方案是使用重载过程。
忘记了另一种可能性:使用常量数组类型的 AAnswer。
听起来像是泛型的工作。
在 XE7 及更高版本中,您可以这样做:
type
TQuestion = class
public
class procedure InsertNewAnswer<T>(AidQuestion: Integer; AAnswer: T);
end;
class procedure TQuestion.InsertNewAnswer<T>(AidQuestion: Integer; AAnswer: T);
begin
case GetTypeKind(T) of
tkString, tkLString, tkUString, tkWString:
InsertNewStringAnswer(AidQuestion, AAnswer);
tkEnumeration:
if GetTypeData(TypeInfo(T))^.BaseType^ = TypeInfo(Boolean) then
InsertNewBoolAnswer(AidQuestion, PBoolean(@AAnswer)^);
...
end;
end;
在 XE7 之前,您可以改为这样做:
type
TQuestion = class
public
class procedure InsertNewAnswer<T>(AidQuestion: Integer; AAnswer: T);
end;
...
uses
..., TypInfo;
class procedure TQuestion.InsertNewAnswer<T>(AidQuestion: Integer; AAnswer: T);
begin
case PTypeInfo(TypeInfo(T)).Kind of
tkString:
InsertNewStringAnswer(AidQuestion, PShortString(@AAnswer)^);
tkLString:
InsertNewStringAnswer(AidQuestion, PAnsiString(@AAnswer)^);
tkUString:
InsertNewStringAnswer(AidQuestion, PUnicodeString(@AAnswer)^);
tkWString:
InsertNewStringAnswer(AidQuestion, PWideString(@AAnswer)^);
tkEnumeration:
if GetTypeData(TypeInfo(T))^.BaseType^ = TypeInfo(Boolean) then
InsertNewBoolAnswer(AidQuestion, PBoolean(@AAnswer)^);
...
end;
end;
无论哪种方式,您都可以这样称呼它:
TQuestion.InsertNewAnswer<String>(id, '...');
TQuestion.InsertNewAnswer<Boolean>(id, true);
...
我有两个几乎相同的程序,唯一的区别是其中一个参数的数据类型。
procedure InsertNewStringAnswer(AidQuestion: Integer; AAnswer: String);
和
procedure InsertNewBoolAnswer(AidQuestion: Integer; AAnswer: Boolean);
我需要根据问题更改答案类型。我是否必须编写两个过程并用第三个过程调用它们,或者有什么方法可以在运行时更改参数 AAnswer 的数据类型?
我正在编辑它以展示我如何构建解决方案。在这种情况下,我使用了 Variant 类型。我无法验证这是否是最佳做法,但它有效:).
procedure InsertNewAnswer(AidQuestion: Integer; AAnswer: Variant);
var
idNextRecord: string;
isBoolean: Boolean;
StrAAnswer: String;
BoolAAnswer: Boolean;
begin
With Connection.queryMain Do
begin
SQL.Clear;
SQL.Text := 'select count(*) as summe from dbo.Answer';
Open;
end;
idNextRecord := Connection.queryMain.FieldByName('summe').Asstring;
With Connection.queryMain Do
begin
SQL.Clear;
//Here I check if the question has a boolean or string answer.
SQL.Text :=('select isBool from dbo.Questions AS ISBOOL WHERE idQuestion= :SQLAidQuestion;');
ParamByName('SQLAidQuestion').AsInteger := AidQuestion;
Prepare;
Open;
end;
//and write it to a Variable.
isBoolean := Connection.queryMain.FieldByName('isBool').AsBoolean;
Connection.queryMain.SQL.Clear;
//I then use a if statement to change the Variant Type accordingly
if isBoolean = True then
begin
//Note that System.Variants does not have VarToBool so I use a workaround
BoolAAnswer := StrToBool(VarToStr(AAnswer));
AAnswer := BoolAAnswer;
Connection.queryMain.SQL.Text :=
('INSERT INTO Frueherkennung.dbo.Answer' +
'(idAnswer, idQuestion, Answer)VALUES(' + idNextRecord +
', :sqlQuestion, :sqlAAnswer);');
Connection.queryMain.ParamByName('sqlQuestion').AsInteger := AidQuestion;
Connection.queryMain.ParamByName('sqlAAnswer').AsBoolean := AAnswer;
end
else
begin
StrAAnswer := VarToStr(AAnswer);
MessageDlg('iSBool:= False', mtError, [mbok], 0);
AAnswer := StrAAnswer;
Connection.queryMain.SQL.Text :=('INSERT INTO Frueherkennung.dbo.Answer' +
'(idAnswer, idQuestion, Answer)VALUES(' + idNextRecord +
', :sqlQuestion, :sqlAAnswer);');
Connection.queryMain.ParamByName('sqlQuestion').AsInteger := AidQuestion;
Connection.queryMain.ParamByName('sqlAAnswer').Asstring := AAnswer
end;
With Connection.queryMain Do
begin
Prepare;
Execute;
SQL.Clear;
end;
end;
谢谢大家的精彩回答。
如果 AAnswer 参数是允许其中几乎所有内容的变体类型,则您可以编写单个函数。
您也可以使用重载关键字保留两个同名的过程。
您还可以让一个过程将 AAnswer 作为指向调用者想要使用的存储的无类型指针。当然在那个时候,问题必须包含必要的信息来决定点是指向布尔值还是指向字符串。
最后这个选项真的不推荐。对我来说,最干净的解决方案是使用重载过程。
忘记了另一种可能性:使用常量数组类型的 AAnswer。
听起来像是泛型的工作。
在 XE7 及更高版本中,您可以这样做:
type
TQuestion = class
public
class procedure InsertNewAnswer<T>(AidQuestion: Integer; AAnswer: T);
end;
class procedure TQuestion.InsertNewAnswer<T>(AidQuestion: Integer; AAnswer: T);
begin
case GetTypeKind(T) of
tkString, tkLString, tkUString, tkWString:
InsertNewStringAnswer(AidQuestion, AAnswer);
tkEnumeration:
if GetTypeData(TypeInfo(T))^.BaseType^ = TypeInfo(Boolean) then
InsertNewBoolAnswer(AidQuestion, PBoolean(@AAnswer)^);
...
end;
end;
在 XE7 之前,您可以改为这样做:
type
TQuestion = class
public
class procedure InsertNewAnswer<T>(AidQuestion: Integer; AAnswer: T);
end;
...
uses
..., TypInfo;
class procedure TQuestion.InsertNewAnswer<T>(AidQuestion: Integer; AAnswer: T);
begin
case PTypeInfo(TypeInfo(T)).Kind of
tkString:
InsertNewStringAnswer(AidQuestion, PShortString(@AAnswer)^);
tkLString:
InsertNewStringAnswer(AidQuestion, PAnsiString(@AAnswer)^);
tkUString:
InsertNewStringAnswer(AidQuestion, PUnicodeString(@AAnswer)^);
tkWString:
InsertNewStringAnswer(AidQuestion, PWideString(@AAnswer)^);
tkEnumeration:
if GetTypeData(TypeInfo(T))^.BaseType^ = TypeInfo(Boolean) then
InsertNewBoolAnswer(AidQuestion, PBoolean(@AAnswer)^);
...
end;
end;
无论哪种方式,您都可以这样称呼它:
TQuestion.InsertNewAnswer<String>(id, '...');
TQuestion.InsertNewAnswer<Boolean>(id, true);
...