传递序数参数

时间:2011-04-04 15:28:53

标签: delphi parameters types delphi-2007 ordinal

是否可以编写一个以任何序数类型作为参数的方法? Inc()或High()的作用方式相同吗?

我正在使用Delphi 2007

3 个答案:

答案 0 :(得分:6)

您需要使用untyped parameter

procedure Foo(const ordinal);

procedure Foo(var ordinal);

当然,你在这样的例程中可以做的事情有点受限,因为你放弃了类型系统。

答案 1 :(得分:1)

找到一种可能的方式,可能不是你所期望的,但是,嘿,我找到了办法!使用Variants。将无类型参数传递给过程的问题在于,您获得了一个普通指针,没有类型信息,因此您无法对其执行任何有用的操作。字节为1字节,最多256个元素的枚举为1字节字节,最多2 ^ 16个元素的枚举为2字节,整数为4字节(除非它们为8)。但是有一种类型允许传递任何内容并关注足够的类型信息以使事情有效:Variant。我故意在Delphi 7中编写了以下示例,以确保我不会意外地使用任何Delphi 2010或Delphi XE的优点。

编辑:更新了代码示例,以处理Variants.VarTypeIsOrdinal被视为序数的任何类型。这包括所有整数类型+布尔值。显然,Enum被视为Byte,所以它也吞下了它。

program Project1;

{$APPTYPE CONSOLE}

uses
  ExceptionLog,
  SysUtils, Variants;

type TSomeEnum = (e0, e1, e2, e3, e4);

procedure DoSomethingWithEnum(V: Variant);
var i: Integer;
    b: Byte;
    lw: LongWord; // Cardinal!
    i64: Integer;
begin
  case VarType(V) of
    varInt64:
      begin
        i64 := V;
        WriteLn(i64);
      end;
    varSmallint, varInteger, varShortInt:
      begin
        i := V;
        WriteLn(i);
      end;
    varByte:
      begin
        b := V;
        WriteLn(b);
      end;
    varWord, varLongWord:
      begin
        lw := V;
        WriteLn(lw);
      end;
    varBoolean:
      begin
        if V then WriteLn('True') else WriteLn('False');
      end;
    else WriteLn('NOT a variant type (type = #' + IntToStr(Ord(VarType(V))));
  end;
end;

var i: Integer;
    b: Byte;
    c: Cardinal;
    enum: TSomeEnum;
    w: Word;
    si: Shortint;

begin
  i := 1;
  b := 2;
  c := 3;
  enum := e4;
  w := 5;
  si := -6;

  DoSomethingWithEnum(i);
  DoSomethingWithEnum(b);
  DoSomethingWithEnum(c);
  DoSomethingWithEnum(enum);
  DoSomethingWithEnum(True);
  DoSomethingWithEnum(w);
  DoSomethingWithEnum(si);

  Readln;
end.

答案 2 :(得分:0)

这样做很困难的原因是Inc(x),Dec(x)和其他像Pred(x)和Succ(x)实际上是由编译器生成的,如果你愿意的话,只是函数样式语法糖在固有的编译器操作上。

正如一些人建议的那样,你可以通过重载实现其中的一些功能,其中一些功能巧妙地使用泛型,其中一些功能具有变体功能。但是没有什么比模仿这些功能更方便,或在功能上完全相同。

例如,编译器为所有有序类型实现Inc(),包括Enums,Integers和这些类型的子范围(经典“Wirth”Pascal现在相当模糊的特性是所有类型都可以在这些类型上定义子范围)。

如果您真的告诉了我们您正在做的事情,可能会更接近。但一般的答案是,不,Inc和Dec都没有源代码,因为这些是编译器原语。如果有函数Inc的RTL源代码,你可以去看看它并进行调整。

inc(x)可以定义为x:= Succ(x),但是,你如何定义Succ(x)?如x:= Inc(x)?你看。在某些时候,编译器“魔术”接管。