단일 객체 []를 params 객체 []에 전달하는 방법


124

다음과 같은 params object []를 사용하는 메서드가 있습니다.

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

이 메서드에 두 개의 개체 배열을 전달하면 제대로 작동합니다.

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

그러나 단일 object []를 전달하면 내 object []를 첫 번째 매개 변수로 사용하지 않고 대신 하나씩 전달하려는 것처럼 모든 요소를 ​​사용합니다.

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

params 배열에 대한 첫 번째 인수로 단일 object []를 어떻게 전달합니까?

답변:


99

간단한 typecast는 컴파일러가이 경우의 의미를 알 수 있도록합니다.

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

배열은 객체의 하위 유형이므로이 모든 것이 작동합니다. 그래도 약간의 이상한 해결책은 동의합니다.


2
params가 작동하는 방식은 불필요 해 보이며 다른 언어에서 익숙해 진 것을 고려할 때 최적이 아닌 C # 디자인입니다. params는 하나의 형식 만 허용하도록 만들 수 있으며,이 경우뿐만 아니라 전체 언어에 도움이되는 기능과 같은 스프레드를 추가 할 수 있습니다. 예를 들어, 모든 param 호출을 Foo (obj [0], obj [1])로 강제 한 다음 Foo (... obj)를 허용하는 별도의 확산 연산자를 가질 수 있습니다.
whitneyland

1
내가 앤더스 헤 즐스 버그를 존경한다는 사실을 분명하게 밝히지 않았다는 것을 깨달았습니다. 그는 세계 최고의 언어 디자이너 중 한 명입니다. 그러나 우리는 충분히 뒤늦게 파악한 사람의 작업, 즉 기술의 개선에 대해 생각할 수 있습니다.
whitneyland

74

params파라미터 수정 호출자에게있어서 여러 인자를 전달하는 단축 구문을 제공한다. params매개 변수를 사용 하여 메소드를 호출하는 방법에는 두 가지가 있습니다 .

1) 매개 변수 유형의 배열을 사용하여 호출합니다.이 경우 params키워드는 효과가없고 배열이 메소드에 직접 전달됩니다.

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

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

2) 또는 확장 된 인수 목록을 사용하여 호출합니다.이 경우 컴파일러는 인수 목록을 임시 배열에 자동으로 래핑하고 메서드에 전달합니다.

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

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


" params object[]"매개 변수 가있는 메소드에 객체 배열을 전달 하려면 다음 중 하나를 수행 할 수 있습니다.

1) 래퍼 배열을 수동으로 만들고 lassevk에서 언급 한대로 직접 메서드에 전달합니다 .

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

2) 또는 Adam이object 언급 한대로 인수를로 캐스팅합니다 .이 경우 컴파일러가 래퍼 배열을 만듭니다.

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


그러나 메서드의 목표가 여러 개체 배열을 처리하는 것이라면 명시적인 " params object[][]"매개 변수를 사용하여 선언하는 것이 더 쉬울 수 있습니다 . 이렇게하면 여러 배열을 인수로 전달할 수 있습니다.

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 );

편집 : Raymond Chen은 새 게시물 에서이 동작과 C # 사양과 관계를 설명합니다 .


8

이것은 LINQ를 포함하는 한 줄 솔루션입니다.

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

3

다음과 같이 다른 object [] 배열로 캡슐화해야합니다.

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

2

이 문제를 해결하는 또 다른 방법 (그렇게 좋은 방법은 아니지만 멋지게 보입니다) :

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

용법:

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

1

한 가지 옵션은 다른 배열로 래핑 할 수 있다는 것입니다.

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

추악하지만 각 항목은 배열이기 때문에 문제를 해결하기 위해 캐스팅 할 수는 없습니다 ... 예를 들어 Foo (params object items) 인 경우 다음과 같이 할 수 있습니다.

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

또는 단일 배열을 취하는 Foo의 또 다른 오버로드 된 인스턴스를 정의 할 수 있습니다.

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 });
}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.