2012-01-15 28 views
18

Nếu tôi đang cố gọi thủ tục có loại bản ghi (không phải đối tượng) làm tham số, có thể bằng cách nào đó chuyển chi tiết của tham số đó "nội tuyến" mà không phải khai báo một biến kiểu đó trước?Truyền tham số bản ghi mà không khai báo nó trước tiên dưới dạng biến

ví dụ giả sử tôi có loại này đơn giản kỷ lục:

type TMyRecord = record 
    AString: string; 
    AnInt: Integer; 
end; 

và khai thủ tục này:

procedure MyProcedure(Rec: TMyRecord); 

Nếu tôi muốn gọi MyProcedure làm tôi phải khai báo một biến kiểu TMyRecord hoặc có thể Tôi làm điều gì đó như:

MyProcedure(TMyRecord("Test", 10)); 

Điều đó không hoạt động (XE2) (gặp lỗi trình biên dịch về nó cũ pecting a ")").

Vì vậy, tôi có thể làm điều gì đó như thế không? Hoặc không thể.

Cảm ơn

+1

Cuộc chiến đang diễn ra bên dưới. Tôi nghĩ rằng câu trả lời lý tưởng sẽ là "Không có cú pháp để tạo một bản ghi tùy ý 'nội tuyến', nhưng * cho bất kỳ bản ghi nào *, bạn có thể đạt được mức độ tiện lợi như nhau bằng [câu trả lời của Brian sau]" –

Trả lời

16

Có thể sử dụng cấu trúc advanced record.

Để biết thêm thông tin về advanced records, hãy xem Records (advanced) section trong trợ giúp Delphi.

Đây là một nguyên mẫu nhỏ để xem làm thế nào nó hoạt động trong trường hợp của bạn để preinitialize mức kỷ lục trong một cuộc gọi chức năng/thủ tục:

Type 
    TRecord = record 
    AString : String; 
    AnInt : Integer; 
    Constructor Create(Const s : String; i : Integer); 
    end; 

constructor TRecord.Create(const s: String; i: Integer); 
begin 
    AString := s; 
    AnInt := i; 
end; 

procedure DoSomething(theRec : TRecord); 
begin 
    WriteLn(theRec.AString, ' ',theRec.AnInt); 
end; 

begin 
    DoSomeThing(TRecord.Create('S',1)); 
    ReadLn; 
end. 

Nhìn vào Delphi RTL, xem các định nghĩa của các loại hồ sơ TPointTRect trong đơn vị system.types (XE2). Chúng xác định một số quá trình xây dựng quá tải Create hàm tạo, được sử dụng ở nhiều nơi để khởi tạo trước cấu trúc bản ghi trong các cuộc gọi hàm/thủ tục.

+0

@KenWhite : Một chức năng duy nhất để bạn có thể tránh tuyên bố một var ở khắp mọi nơi bạn chỉ muốn vượt qua một vài giá trị, không có vẻ như "rất nhiều mã" với tôi. Đó là loại được khai báo ở nơi khác là tranh luận (miễn là nó không có trong thư viện). –

+0

Tôi sẽ không tham gia vào 'cuộc chiến' đang xảy ra ở đây, nhưng theo như sự khác biệt giữa cách tiếp cận này và của Brian, tôi vẫn không chắc mình thích cái nào hơn ... –

+0

Vì lý do lịch sử, nó mang lại lợi ích giải pháp thay thế. –

16

Câu hỏi bạn đang yêu cầu liên quan đến khả năng đọc mã và có giải pháp tránh phải tạo biến. VCL sử dụng giải pháp này với các hồ sơ TPointTRect.

xem xét định nghĩa của TPoint:

type 
    TPoint = record 
    X,Y integer 
    end; 

Để vượt qua một TPoint đến một thủ tục bạn có thể làm:

var 
    MyPoint : TPoint; 

begin 
    MyPoint.X := 5; 
    MyPoint.Y := 7; 
    DoSomething(MyPoint); 
end; 

Điều này là tốt nhưng phải mất 3 dòng khi người ta cũng có thể sử dụng các nhà máy chức năng Point:

begin 
    DoSomething(Point(5,7)); 
end; 

Trong Delphi, một chức năng đã được công bố như sau:

function Point(X, Y : integer) : TPoint; 
begin 
    Result.X := X; 
    Result.Y := Y; 
end; 

Sau đó bạn có thể gọi chức năng này 'inline' để tạo ra các kỷ lục 'trên bay' để nhanh chóng Bạn sẽ thấy tương tự đã được quy định TRect v.v.Tôi thường đặt như một chức năng nhà máy cùng với việc kê khai hồ sơ như sau, ngay cả khi tôi không có kế hoạch sử dụng chúng được nêu ra:

type 
    TMyRecord = record 
    A : integer; 
    B : string; 
    end; 

function MyRecord(A : integer; const B : string) : TMyRecord; 
begin 
    Result.A := A; 
    Result.B := B; 
end; 

Sử dụng kỹ thuật này có thể cải thiện khả năng đọc mã và cũng đảm bảo rằng bạn don vô tình bỏ qua việc thiết lập một phần tử bản ghi.

+5

Tôi nghĩ rằng nó _does_ trả lời câu hỏi ("Vì vậy, tôi có thể làm một cái gì đó như thế?" - Brian Frost cung cấp một cách để làm một cái gì đó như thế :)) –

+2

@KenWhite: Một chức năng duy nhất 'MyRect' để bạn có thể tránh tuyên bố một var ở khắp mọi nơi bạn chỉ muốn vượt qua một vài giá trị, không có vẻ như "rất nhiều mã" với tôi. Đó là loại được khai báo ở nơi khác là hoàn toàn tranh luận trong giải pháp này. –

+0

@KenWhite: Nếu chúng tôi chỉ trả lời câu hỏi chính xác, SO sẽ ít hữu ích hơn rất nhiều. Có lẽ cả Brian và LU RD nên mở đầu câu trả lời của họ với "Không, không thể làm được, nhưng đây là một cách giải quyết", nhưng theo quan điểm của tôi, đó là ngụ ý trả lời của họ với một cái gì đó khác không phải là Ngắn/Không. –

2

Nó sẽ rất tuyệt! Nhưng không.

Nếu thông qua nội tuyến thực sự là mục tiêu của bạn, thì có lẽ Thông số mảng mở sẽ phù hợp với bạn.

Procedure MyProcedure(const Vars: Array of Variant); 
begin 
    ShowMessage(VarToStr(Vars[0])+' '+VarToStr(Vars[1])); 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    MyProcedure(['Test', 12]); 
end; 

Bạn cũng có thể chuyển một mảng của Const, về cơ bản là một mảng của TVarRec là bản ghi biến thể cũng bao gồm thông tin loại như VType. Đây là công cụ thú vị ..

Một bài viết tuyệt vời có thể được tìm thấy trên Delphi Corner Rudy ở đây: Rudy's Delphi Corner, Open Array Parameters

+1

-1. Tôi thấy không có lý do để làm điều đó theo cách này. Nếu bạn sẽ không vượt qua toàn bộ bản ghi, sẽ tốt hơn nếu bạn chỉ khai báo hai tham số đã nhập riêng biệt. Sau đó trình biên dịch có thể cho bạn biết liệu bạn có mọi thứ hay không, thay vì chức năng phải kiểm tra nó khi chạy. –

+0

Wow, a -1 để cung cấp cách chuyển một bản ghi mà không tạo một biến cục bộ? Tôi không thấy câu trả lời của tôi không được áp dụng cho câu hỏi .. Tôi không thấy bỏ phiếu, nhưng bỏ phiếu? một lần nữa, wow. –

+1

Nếu nó không áp dụng cho câu hỏi, tôi đã gắn cờ nó. Câu trả lời của bạn áp dụng cho câu hỏi, nhưng đó là một câu trả lời tệ hại bởi vì nó có một nhiệm vụ có thể dễ dàng được gõ mạnh mẽ và làm cho nó yếu gõ và cú pháp lẻ. –

3

Chỉ có vui vẻ với ý tưởng John Easley của:

type TRec = record 
    X: string; 
    Y: Integer; 
end; 

procedure TestRec(const Rec: array of const); 
var 
    R: TRec; 

begin 
    R.X:= string(Rec[0].VUnicodeString); 
    R.Y:= Rec[1].VInteger; 
    ShowMessage(R.X + IntToStr(R.Y)); 
end; 

procedure TForm1.Button7Click(Sender: TObject); 
begin 
    TestRec(['Test', 22]); 
end; 

Có thể vượt qua cánh đồng kỷ lục như thông số array of const và chỉ định các thông số này cho biến bản ghi cục bộ.

+0

Tôi thích nó, nhưng tôi thiên vị :) –

+1

-1. Đó là phức tạp không cần thiết. Khai báo hàm với hai tham số, một tham số cho mỗi trường. Cung cấp cho họ các loại cụ thể. Loại bỏ các dấu ngoặc từ trang cuộc gọi. –

+0

@RobKennedy - Đề xuất của bạn rất buồn tẻ. Lập trình phải vui vẻ. :) – kludg

Các vấn đề liên quan