Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Excel 从VBA到Delphi的转换(可选参数问题)_Excel_Delphi_Vba - Fatal编程技术网

Excel 从VBA到Delphi的转换(可选参数问题)

Excel 从VBA到Delphi的转换(可选参数问题),excel,delphi,vba,Excel,Delphi,Vba,目前,我正在将一个用VBA编写的项目转换为Delphi,在转换一些带有可选参数的SUB时遇到了一个问题。 比如说,有一个子声明(仅举一个例子,实际的子声明最多有10个可选参数): 该Sub随后可被称为如下所示: Call SetMark (15, 100,,,"135") Call SetMark (100, 100, 8,, "My text here..", "") 'a lot of calls here 可选的参数在这里非常灵活,您可以省略它们中的任何一个,也可

目前,我正在将一个用VBA编写的项目转换为Delphi,在转换一些带有
可选
参数的SUB时遇到了一个问题。 比如说,有一个子声明(仅举一个例子,实际的子声明最多有10个可选参数):

该Sub随后可被称为如下所示:

    Call SetMark (15, 100,,,"135")
    Call SetMark (100, 100, 8,, "My text here..", "")
    'a lot of calls here
可选的
参数在这里非常灵活,您可以省略它们中的任何一个,也可以为它们中的任何一个赋值。与德尔福不同

Procedure SetMark
    (x0: real; y0: real, 
            TextOffset: Integer =5;
     TextBefore: ShortString = '';
     Text: ShortString = '';
     TextAfter: ShortString = 'mm';
     Color: ShortString = 'FFFFFF';
     ArrowPresent: Boolean = True);
似乎您不能仅复制VBA调用:

SetMark (15, 100,,,'135');// error here 
所以,问题是:有没有办法将SUB转换为Delphi程序,保持参数的灵活性? 我的第一个想法是使用默认参数,但它不起作用。 现在看来,在Delphi中,我必须直接传递列表中的所有参数及其值,但这意味着要检查和正确移植VBA调用需要做大量工作

有什么想法吗

有没有办法将VBA子程序转换为Delphi程序,同时保持参数的灵活性

没有办法做到这一点——除了在列表末尾之外,根本不存在省略参数的灵活性

对于自动化对象的方法,您可以使用命名参数,如下所述:但是,我非常建议您不要仅仅为了获得该功能而将类实现为自动化对象

每当你在不同的语言之间切换时,你会发现不方便的差异。这是不可避免的。最好的办法是设法用新的语言来解决问题,而不是把旧语言中的习语强加到新语言中去


在这种情况下,您可能希望使用或作为减轻这种不便的方法。

为了扩展使用参数对象的重构思想,您可以声明如下记录:

 TSetMarkParams = record
   x0 : double; 
   y0 : double; 
   TextOffset : integer;
   TextBefore : string;
   Text : string;
   TextAfter : string;
   Color : string;
   ArrowPresent : boolean;
   constructor Create(Ax0, Ay0 : double);
 end;
并实现构造函数以填充默认值,如下所示:

 constructor TSetMarkParams.Create(Ax0, Ay0 : double);
 begin
   x0 := Ax0;
   y0 := Ay0;
   TextOffset := 5;
   TextBefore := '';
   Text := '';
   TextAfter := 'mm';
   Color := 'FFFFFF';
   AllowPresent := true;
 end;
您的程序将有以下签名:

 procedure SetMark(ASetMarkParams : TSetMarkParams);
然后,您可以使用
SetMark(15100,,'135')的示例呼叫方式:

 var 
   LSetMarkParams : TSetMarkParams
 begin
   LSetMarkParams := TSetMarkParams.Create(15, 100);
   LSetMarkParams.Text := '135';
   SetMark(LSetMarkParams);
 end;

作为附带的好处,上面的内容更具可读性,因为它避免了您在返回调试一个麻烦的方法调用时盲目尝试计数逗号。

顺便说一句,您确实不应该使用
ShortString
。这已经被弃用多年了。使用本机字符串类型,
string
。另外,切题地说,
real
是一种仅为兼容而存在的遗留类型(它是
double
的别名)。最好在Delphi代码中声明一个
double
,就像VB代码那样。是的。重载将是我的首选解决方案。请指定如何实现重载,以区分对指定参数
Text
textfeater
的调用,例如。@J。。。构造函数是特殊的。当您调用它时,一个新对象被实例化,然后初始化。另一方面,记录构造函数只是初始化。它不实例化。我习惯于看到这样的代码,
obj:=TMyClass.Create
,并且知道我需要将它与调用
obj.Free
配对。记录并非如此。我发现使用
rec:=TMyRec.Create会引起混淆。
obj
是值类型还是参考类型?通过保留构造函数对引用类型的使用,我可以确信我知道我在处理什么。@J。。。另一个问题是记录上不允许使用无参数构造函数。如果你是一个
FreeAndNil
er,那么你可能会意外地将记录传递给
FreeAndNil
,从而被发现。事实上,这确实是停止使用
FreeAndNil
的原因,不是吗?最后,我不喜欢在实例上调用构造函数。我可以写
rec.Create(666)。我宁愿不允许那样。我的约定是一个名为
New
的静态类方法。所以我会初始化这样一个记录:
rec:=TMyRec.New
。通过遵循这种惯例,我发现更容易确定自己知道自己在处理什么。@J。。。现在在这个实例中,asker使用的是delphi7,既不能使用构造函数,也不能使用静态类函数。裸体功能是他唯一的选择。
 var 
   LSetMarkParams : TSetMarkParams
 begin
   LSetMarkParams := TSetMarkParams.Create(15, 100);
   LSetMarkParams.Text := '135';
   SetMark(LSetMarkParams);
 end;