Cách truyền một đối tượng [] cho một đối tượng params []


124

Tôi có một phương thức lấy đối tượng params [], chẳng hạn như:

void Foo(params object[] items)
{
    Console.WriteLine(items[0]);
}

Khi tôi truyền hai mảng đối tượng cho phương thức này, nó hoạt động tốt:

Foo(new object[]{ (object)"1", (object)"2" }, new object[]{ (object)"3", (object)"4" } );
// Output: System.Object[]

Nhưng khi tôi vượt qua một đối tượng duy nhất [], nó không lấy đối tượng của tôi [] làm thông số đầu tiên, thay vào đó, nó lấy tất cả các yếu tố như tôi muốn truyền từng cái một:

Foo(new object[]{ (object)"1", (object)"2" });
// Output: 1, expected: System.Object[]

Làm cách nào để tôi chuyển một đối tượng duy nhất [] làm đối số đầu tiên cho mảng params?

Câu trả lời:


99

Một typecast đơn giản sẽ đảm bảo trình biên dịch biết ý của bạn trong trường hợp này.

Foo((object)new object[]{ (object)"1", (object)"2" }));

Vì một mảng là một kiểu con của đối tượng, tất cả đều hoạt động. Mặc dù vậy, tôi sẽ đồng ý với một giải pháp kỳ lạ.


2
cách thức hoạt động của params dường như không cần thiết và thiết kế c # tối ưu, dựa trên những gì chúng ta đã sử dụng trong các ngôn ngữ khác. params có thể đã được thực hiện để chỉ chấp nhận một hình thức và một tính năng giống như trải rộng có thể được thêm vào sẽ có lợi cho toàn bộ ngôn ngữ, không chỉ trong trường hợp này. ví dụ: chúng ta có thể buộc tất cả các lệnh gọi param là Foo (obj [0], obj [1]), và sau đó có một toán tử trải rộng riêng biệt cho phép Foo (... obj).
whitneyland

1
nhận ra tôi đã không nói rõ rằng tôi rất tôn trọng anders hejlsberg, anh ấy là một trong những nhà thiết kế ngôn ngữ giỏi nhất thế giới. nhưng chúng ta có thể nghĩ về những cải tiến cho công việc của bất kỳ ai khi có đủ tầm nhìn, do đó là công nghệ.
whitneyland

74

Công cụ paramssửa đổi tham số cung cấp cho người gọi một cú pháp phím tắt để truyền nhiều đối số cho một phương thức. Có hai cách để gọi một phương thức với mộtparams tham số:

1) Gọi với một mảng kiểu tham số, trong trường hợp đó paramstừ khóa không có hiệu lực và mảng được truyền trực tiếp vào phương thức:

object[] array = new[] { "1", "2" };

// Foo receives the 'array' argument directly.
Foo( array );

2) Hoặc, gọi với một danh sách các đối số mở rộng, trong trường hợp đó, trình biên dịch sẽ tự động bao bọc danh sách các đối số trong một mảng tạm thời và chuyển nó sang phương thức:

// Foo receives a temporary array containing the list of arguments.
Foo( "1", "2" );

// This is equivalent to:
object[] temp = new[] { "1", "2" );
Foo( temp );


Để truyền một mảng đối tượng cho một phương thức có params object[]tham số "", bạn có thể:

1) Tạo một mảng bao bọc bằng tay và truyền trực tiếp vào phương thức, như được đề cập bởi lassevk :

Foo( new object[] { array } );  // Equivalent to calling convention 1.

2) Hoặc, đưa đối số tới object, như Adam đã đề cập , trong trường hợp đó, trình biên dịch sẽ tạo mảng trình bao cho bạn:

Foo( (object)array );  // Equivalent to calling convention 2.


Tuy nhiên, nếu mục tiêu của phương thức là xử lý nhiều mảng đối tượng, có thể dễ dàng khai báo nó với params object[][]tham số " " rõ ràng . Điều này sẽ cho phép bạn vượt qua nhiều mảng dưới dạng đối số:

void Foo( params object[][] arrays ) {
  foreach( object[] array in arrays ) {
    // process array
  }
}

...
Foo( new[] { "1", "2" }, new[] { "3", "4" } );

// Equivalent to:
object[][] arrays = new[] {
  new[] { "1", "2" },
  new[] { "3", "4" }
};
Foo( arrays );

Chỉnh sửa: Raymond Chen mô tả hành vi này và cách nó liên quan đến đặc tả C # trong một bài đăng mới .


8

Đây là một giải pháp một dòng liên quan đến LINQ.

var elements = new String[] { "1", "2", "3" };
Foo(elements.Cast<object>().ToArray())

3

Bạn cần gói nó vào một mảng [] đối tượng khác, như thế này:

Foo(new Object[] { new object[]{ (object)"1", (object)"2" }});

2

Một cách khác để giải quyết vấn đề này (đó không phải là cách thực hành tốt nhưng có vẻ đẹp):

static class Helper
{
    public static object AsSingleParam(this object[] arg)
    {
       return (object)arg;
    }
}

Sử dụng:

f(new object[] { 1, 2, 3 }.AsSingleParam());

1

Một tùy chọn là bạn có thể gói nó vào một mảng khác:

Foo(new object[]{ new object[]{ (object)"1", (object)"2" } });

Khá xấu xí, nhưng vì mỗi mục là một mảng, bạn không thể bỏ nó để làm cho vấn đề biến mất ... chẳng hạn như nếu đó là Foo (mục đối tượng params), thì bạn có thể làm:

Foo((object) new object[]{ (object)"1", (object)"2" });

Ngoài ra, bạn có thể thử xác định một phiên bản Foo bị quá tải khác, chỉ mất một mảng duy nhất:

void Foo(object[] item)
{
    // Somehow don't duplicate Foo(object[]) and
    // Foo(params object[]) without making an infinite
    // recursive call... maybe something like
    // FooImpl(params object[] items) and then this
    // could invoke it via:
    // FooImpl(new object[] { item });
}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.