是否可以使用 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);
...