development

메소드 호출자에게 여러 값 반환

big-blog 2020. 2. 25. 22:49
반응형

메소드 호출자에게 여러 값 반환


이 질문C ++ 버전을 읽었 지만 실제로 이해하지 못했습니다.

누군가 어떻게 할 수 있는지 명확하게 설명 할 수 있습니까?


.NET 4.0 이상의 Tuple을 사용하십시오 :

예를 들어 :

public Tuple<int, int> GetMultipleValue()
{
     return Tuple.Create(1,2);
}

두 값 한과 튜플 Item1Item2속성으로.


C # 7이 릴리스되었으므로 포함 된 새로운 Tuples 구문을 사용할 수 있습니다.

(string, string, string) LookupName(long id) // tuple return type
{
    ... // retrieve first, middle and last from data storage
    return (first, middle, last); // tuple literal
}

다음과 같이 사용할 수 있습니다.

var names = LookupName(id);
WriteLine($"found {names.Item1} {names.Item3}.");

요소에 이름을 제공 할 수도 있습니다 ( "Item1", "Item2"등이 아님). 서명 또는 리턴 메소드에 이름을 추가하여이를 수행 할 수 있습니다.

(string first, string middle, string last) LookupName(long id) // tuple elements have names

또는

return (first: first, middle: middle, last: last); // named tuple elements in a literal

그것들은 또한 해체 될 수 있는데, 이것은 아주 좋은 새로운 기능입니다 :

(string first, string middle, string last) = LookupName(id1); // deconstructing declaration

체크 아웃 이 링크를 무엇을 할 수 있는지에 더 많은 예제를 볼 수 :)


세 가지 다른 방법을 사용할 수 있습니다

1. ref / out 파라미터

심판 사용 :

static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    int add = 0;
    int multiply = 0;
    Add_Multiply(a, b, ref add, ref multiply);
    Console.WriteLine(add);
    Console.WriteLine(multiply);
}

private static void Add_Multiply(int a, int b, ref int add, ref int multiply)
{
    add = a + b;
    multiply = a * b;
}

밖으로 사용 :

static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    int add;
    int multiply;
    Add_Multiply(a, b, out add, out multiply);
    Console.WriteLine(add);
    Console.WriteLine(multiply);
}

private static void Add_Multiply(int a, int b, out int add, out int multiply)
{
    add = a + b;
    multiply = a * b;
}

2. 구조체 / 클래스

구조체를 사용하여 :

struct Result
{
    public int add;
    public int multiply;
}
static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    var result = Add_Multiply(a, b);
    Console.WriteLine(result.add);
    Console.WriteLine(result.multiply);
}

private static Result Add_Multiply(int a, int b)
{
    var result = new Result
    {
        add = a * b,
        multiply = a + b
    };
    return result;
}

수업 사용 :

class Result
{
    public int add;
    public int multiply;
}
static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    var result = Add_Multiply(a, b);
    Console.WriteLine(result.add);
    Console.WriteLine(result.multiply);
}

private static Result Add_Multiply(int a, int b)
{
    var result = new Result
    {
        add = a * b,
        multiply = a + b
    };
    return result;
}

3. 튜플

튜플 클래스

static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    var result = Add_Multiply(a, b);
    Console.WriteLine(result.Item1);
    Console.WriteLine(result.Item2);
}

private static Tuple<int, int> Add_Multiply(int a, int b)
{
    var tuple = new Tuple<int, int>(a + b, a * b);
    return tuple;
}

C # 7 튜플

static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    (int a_plus_b, int a_mult_b) = Add_Multiply(a, b);
    Console.WriteLine(a_plus_b);
    Console.WriteLine(a_mult_b);
}

private static (int a_plus_b, int a_mult_b) Add_Multiply(int a, int b)
{
    return(a + b, a * b);
}

C #에서는이 작업을 수행 할 수 없습니다. 당신이 할 수있는 일은 out매개 변수가 있거나 자신의 클래스를 반환하는 것입니다 (또는 불변의 경우 구조체).

매개 변수 사용
public int GetDay(DateTime date, out string name)
{
  // ...
}
커스텀 클래스 (또는 구조체) 사용하기
public DayOfWeek GetDay(DateTime date)
{
  // ...
}

public class DayOfWeek
{
  public int Day { get; set; }
  public string Name { get; set; }
}

여러 값을 반환하려는 경우 반환하려는 값이 포함 된 클래스 / 구조를 반환하거나 다음과 같이 매개 변수에 "out"키워드를 사용할 수 있습니다.

public void Foo(int input, out int output1, out string output2, out string errors) {
    // set out parameters inside function
}

이전 포스터가 맞습니다. C # 메서드에서 여러 값을 반환 할 수 없습니다. 그러나 몇 가지 옵션이 있습니다.

  • 여러 멤버를 포함하는 구조체를 반환
  • 클래스의 인스턴스를 반환
  • 출력 매개 변수 사용 ( out 또는 ref 키워드 사용)
  • 사전 또는 키-값 쌍을 출력으로 사용

여기의 장단점은 종종 파악하기가 어렵습니다. 구조체를 반환하는 경우 구조체는 값 형식이며 스택에 전달되므로 크기가 작아야합니다. 클래스의 인스턴스를 반환하면 문제를 피하기 위해 사용할 수있는 디자인 패턴이 있습니다 .C #은 참조로 개체를 전달하기 때문에 클래스 멤버를 수정할 수 있습니다 (VB에서와 같이 ByVal이 없음) ).

마지막으로 출력 매개 변수를 사용할 수 있지만 몇 개 (예 : 3 개 이하)의 매개 변수 만있는 경우 시나리오의 사용을 제한합니다. 그렇지 않으면 유지 관리가 어려워집니다. 또한 출력 매개 변수를 사용하면 반환 값에 무언가를 추가해야 할 때마다 메서드 서명이 변경되어야하지만 구조체 또는 클래스 인스턴스를 반환하면 메서드 서명을 수정하지 않고 멤버를 추가 할 수 있기 때문에 민첩성을 저해 할 수 있습니다.

아키텍처 관점에서 키-값 쌍 또는 사전을 사용하지 않는 것이 좋습니다. 이 스타일의 코딩에는 메서드를 사용하는 코드에서 "비밀 지식"이 필요합니다. 키의 의미와 값의 의미를 미리 알고 있어야하며 내부 구현 작업을 수행하는 개발자가 사전 또는 KVP 작성 방식을 변경하면 전체 애플리케이션에서 장애 단계를 쉽게 작성할 수 있습니다.


클래스 인스턴스 를 반환 하거나 매개 변수를 사용 합니다 . 다음은 출력 매개 변수의 예입니다.

void mymethod(out int param1, out int param2)
{
    param1 = 10;
    param2 = 20;
}

다음과 같이 호출하십시오.

int i, j;
mymethod(out i, out j);
// i will be 20 and j will be 10

이를 수행하는 몇 가지 방법이 있습니다. ref매개 변수 를 사용할 수 있습니다 .

int Foo(ref Bar bar) { }

이것은 함수에 대한 참조를 전달하여 함수가 호출 코드의 스택에서 객체를 수정할 수 있도록합니다. 이것은 기술적으로 "반환 된"값이 아니지만 함수가 비슷한 것을 수행하도록하는 방법입니다. 위의 코드에서 함수는 intand (잠재적으로) modify를 반환 합니다 bar.

또 다른 유사한 방법은 out매개 변수 를 사용하는 것 입니다. out파라미터는 동일 ref추가적인 컴파일러 시행 규칙 파라미터. 이 규칙은 out매개 변수를 함수에 전달하면 반환하기 전에 해당 함수가 값을 설정해야한다는 것입니다. 이 규칙 외에도 out매개 변수 매개 변수와 동일하게 작동합니다 ref.

마지막 접근 방식 (및 대부분의 경우 가장 좋은 방법)은 두 값을 캡슐화하고 함수가 다음을 반환하도록 허용하는 형식을 만드는 것입니다.

class FooBar 
{
    public int i { get; set; }
    public Bar b { get; set; }
}

FooBar Foo(Bar bar) { }

이 최종 접근 방식은 더 단순하고 읽기 쉽고 이해하기 쉽습니다.


아니요, 적어도 Python에서는 수행 할 수있는 방식이 아닌 C # (C # 7보다 낮은 버전의 경우)의 함수에서 여러 값을 반환 할 수 없습니다.

그러나 몇 가지 대안이 있습니다.

여러 값이 포함 된 객체 유형의 배열을 반환 할 수 있습니다.

private object[] DoSomething()
{
    return new [] { 'value1', 'value2', 3 };
}

out매개 변수 를 사용할 수 있습니다 .

private string DoSomething(out string outparam1, out int outparam2)
{
    outparam1 = 'value2';
    outparam2 = 3;
    return 'value1';
}

C # 4에서는 튜플에 대한 내장 지원을 사용하여이를 쉽게 처리 할 수 ​​있습니다.

그 동안 두 가지 옵션이 있습니다.

먼저 ref 또는 out 매개 변수를 사용하여 매개 변수에 값을 할당하면 호출 루틴으로 다시 전달됩니다.

이것은 다음과 같습니다

void myFunction(ref int setMe, out int youMustSetMe);

둘째, 반환 값을 구조 또는 클래스로 마무리하고 해당 구조의 멤버로 다시 전달할 수 있습니다. KeyValuePair는 2에서 잘 작동합니다. 2 이상에서는 사용자 정의 클래스 또는 구조체가 필요합니다.


C # 7에는 새로운 Tuple구문이 있습니다.

static (string foo, int bar) GetTuple()
{
    return ("hello", 5);
}

이것을 레코드로 반환 할 수 있습니다.

var result = GetTuple();
var foo = result.foo
// foo == "hello"

새로운 해체 구문을 사용할 수도 있습니다.

(string foo) = GetTuple();
// foo == "hello"

그러나 직렬화에주의,이 모든 문법 설탕입니다 - 실제 컴파일 된 코드에서이 될 것이다 Tupel<string, int>(같은 허용 대답 당 과) Item1Item2대신 foo하고 bar. 즉, 직렬화 (또는 역 직렬화)는 해당 속성 이름을 대신 사용합니다.

따라서 직렬화의 경우 레코드 클래스를 선언하고 대신 해당 클래스를 리턴하십시오.

C # 7의 새로운 기능은 out매개 변수에 대한 향상된 구문입니다 . 이제 out인라인을 선언 할 수 있는데 , 이는 일부 상황에 더 적합합니다.

if(int.TryParse("123", out int result)) {
    // Do something with result
}

그러나 대부분 자신의 함수가 아닌 .NET의 자체 라이브러리에서 이것을 사용합니다.


일부 답변은 매개 변수를 사용 하는 것이 좋지만 비동기 메서드에서는 작동하지 않기 때문에 사용하지 않는 것이 좋습니다 . 자세한 내용은 이것을 참조하십시오.

다른 답변은 Tuple을 사용하여 언급했지만 C # 7.0에 도입 된 새로운 기능을 사용하는 것이 좋습니다.

(string, string, string) LookupName(long id) // tuple return type
{
    ... // retrieve first, middle and last from data storage
    return (first, middle, last); // tuple literal
}

var names = LookupName(id);
WriteLine($"found {names.Item1} {names.Item3}.");

자세한 내용은 여기를 참조하십시오 .


이 "KeyValuePair"를 사용해보십시오

private KeyValuePair<int, int> GetNumbers()
{
  return new KeyValuePair<int, int>(1, 2);
}


var numbers = GetNumbers();

Console.WriteLine("Output : {0}, {1}",numbers.Key, numbers.Value);

출력 :

출력 : 1, 2


클래스, 구조, 컬렉션 및 배열은 여러 값을 포함 할 수 있습니다. 함수에서 출력 및 기준 파라미터를 설정할 수도 있습니다. 튜플을 사용하여 동적 및 기능적 언어에서 여러 값을 반환 할 수 있지만 C #에서는 반환 할 수 없습니다.


주로 두 가지 방법이 있습니다. 1. out / ref 파라미터 사용 2. 객체 배열 반환


기본 Two방법 은 다음과 같습니다 .

1) out매개 변수 로 ' ' 사용 4.0 및 부 버전 모두에 대해 'out'을 사용할 수 있습니다.

'out'의 예 :

using System;

namespace out_parameter
{
  class Program
   {
     //Accept two input parameter and returns two out value
     public static void rect(int len, int width, out int area, out int perimeter)
      {
        area = len * width;
        perimeter = 2 * (len + width);
      }
     static void Main(string[] args)
      {
        int area, perimeter;
        // passing two parameter and getting two returning value
        Program.rect(5, 4, out area, out perimeter);
        Console.WriteLine("Area of Rectangle is {0}\t",area);
        Console.WriteLine("Perimeter of Rectangle is {0}\t", perimeter);
        Console.ReadLine();
      }
   }
}

산출:

사각형의 면적은 20

직사각형의 둘레는 18

* 참고 : * out-keyword는 실제 변수 위치가 호출 된 메소드의 스택에 복사되어 동일한 위치를 다시 쓸 수있는 매개 변수를 설명합니다. 이는 호출 메소드가 변경된 매개 변수에 액세스 함을 의미합니다.

2) Tuple<T>

튜플의 예 :

사용하여 여러 DataType 값 반환 Tuple<T>

using System;

class Program
{
    static void Main()
    {
    // Create four-item tuple; use var implicit type.
    var tuple = new Tuple<string, string[], int, int[]>("perl",
        new string[] { "java", "c#" },
        1,
        new int[] { 2, 3 });
    // Pass tuple as argument.
    M(tuple);
    }

    static void M(Tuple<string, string[], int, int[]> tuple)
    {
    // Evaluate the tuple's items.
    Console.WriteLine(tuple.Item1);
    foreach (string value in tuple.Item2)
    {
        Console.WriteLine(value);
    }
    Console.WriteLine(tuple.Item3);
    foreach (int value in tuple.Item4)
    {
        Console.WriteLine(value);
    }
    }
}

산출

perl
java
c#
1
2
3

참고 : Tuple 사용은 Framework 4.0 이상에서 유효합니다 . Tuple유형은입니다 class. 메모리에서 관리되는 힙의 별도 위치에 할당됩니다. 를 만든 후에 Tuple는의 값을 변경할 수 없습니다 fields. 이것은 Tuple더 비슷합니다 struct.


많은 방법이 있습니다. 그러나 새로운 객체 또는 구조 또는 이와 같은 것을 만들고 싶지 않으면 C # 7.0 이후에 다음과 같이 할 수 있습니다 .

 (string firstName, string lastName) GetName(string myParameter)
    {
        var firstName = myParameter;
        var lastName = myParameter + " something";
        return (firstName, lastName);
    }

    void DoSomethingWithNames()
    {
        var (firstName, lastName) = GetName("myname");

    }

델리게이트를받는 메소드는 호출자에게 여러 값을 제공 할 수 있습니다. 이것은 내 대답 에서 빌려 왔으며 Hadas의 대답 에서 약간 사용되었습니다 .

delegate void ValuesDelegate(int upVotes, int comments);
void GetMultipleValues(ValuesDelegate callback)
{
    callback(1, 2);
}

호출자는 람다 (또는 명명 된 함수)를 제공하고 대리자의 변수 이름을 복사하여 인텔리전스 지원을 제공합니다.

GetMultipleValues((upVotes, comments) =>
{
     Console.WriteLine($"This post has {upVotes} Up Votes and {comments} Comments.");
});

OOP 방식으로 다음과 같은 클래스를 사용하십시오.

class div
{
    public int remainder;

    public int quotient(int dividend, int divisor)
    {
        remainder = ...;
        return ...;
    }
}

함수 멤버는 대부분의 호출자가 주로 관심을 갖는 몫을 리턴합니다. 또한 나머지는 데이터 멤버로 저장하며, 나중에 호출자가 쉽게 액세스 할 수 있습니다.

이 방법을 사용하면 많은 추가 "반환 값"을 가질 수 있으며 데이터베이스 또는 네트워킹 호출을 구현할 때 매우 유용합니다. 많은 오류 메시지가 필요할 수 있지만 오류가 발생한 경우에만 유용합니다.

OP가 참조하는 C ++ 질문 에도이 솔루션을 입력했습니다.


에서 게시물 위에서 말했듯이 기사, 당신은 세 가지 옵션을 사용할 수 있습니다.

KeyValuePair 가 가장 빠른 방법입니다.

아웃 제이다.

튜플 이 가장 느립니다.

어쨌든 이것은 시나리오에 가장 적합한 것에 달려 있습니다.


C #의 향후 버전에는 명명 된 튜플이 포함될 예정입니다. 데모 https://channel9.msdn.com/Events/Build/2016/B889에 대한이 channel9 세션을 살펴보십시오

튜플은 13:00으로 건너 뜁니다. 이것은 다음과 같은 것들을 허용합니다 :

(int sum, int count) Tally(IEnumerable<int> list)
{
// calculate stuff here
return (0,0)
}

int resultsum = Tally(numbers).sum

(비디오에서 불완전한 예)


동적 객체를 사용할 수 있습니다. Tuple보다 가독성이 더 좋다고 생각합니다.

static void Main(string[] args){
    var obj = GetMultipleValues();
    Console.WriteLine(obj.Id);
    Console.WriteLine(obj.Name);
}

private static dynamic GetMultipleValues() {
    dynamic temp = new System.Dynamic.ExpandoObject();
    temp.Id = 123;
    temp.Name = "Lorem Ipsum";
    return temp;
}

<--Return more statements like this you can --> 

public (int,string,etc) Sample( int a, int b)  
{
    //your code;
    return (a,b);  
}

당신은 같은 코드를받을 수 있습니다

(c,d,etc) = Sample( 1,2);

나는 그것이 작동하기를 바랍니다.


그것을하는 방법 :

1) KeyValuePair (최고 성능-0.32ns) :

    KeyValuePair<int, int> Location(int p_1, int p_2, int p_3, int p_4)
    {                 
         return new KeyValuePair<int,int>(p_2 - p_1, p_4-p_3);
    }

2) 튜플-5.40ns :

    Tuple<int, int> Location(int p_1, int p_2, int p_3, int p_4)
    {
          return new Tuple<int, int>(p_2 - p_1, p_4-p_3);
    }

3) out (1.64 ns) 또는 ref 4) 나만의 커스텀 클래스 / 구조체 만들기

ns-> 나노초

참조 : 다중 반환 값 .


당신은 이것을 시도 할 수 있습니다

public IEnumerable<string> Get()
 {
     return new string[] { "value1", "value2" };
 }

OperationResult를 사용할 수도 있습니다

public OperationResult DoesSomething(int number1, int number2)
{
// Your Code
var returnValue1 = "return Value 1";
var returnValue2 = "return Value 2";

var operationResult = new OperationResult(returnValue1, returnValue2);
return operationResult;
}

오늘날 프로그래머에게는 시간과 잊을 수없는 방법이 필요합니다. 간단하고 작동하며 빠른 솔루션 :

private int[] SumAndSub(int A, int B)
{
    return new[] { A + B , A - B };
}

어딘가에 그것을 사용;

var results = SumAndSub(20, 5);
int sum = results[0];
int sub = results[0];

참고 URL : https://stackoverflow.com/questions/748062/return-multiple-values-to-a-method-caller



반응형