답변:
C # 7 이상에서는 이 답변을 참조하십시오 .
이전 버전에서는 .NET 4.0+의 Tuple을 사용할 수 있습니다 .
예를 들어 :
public Tuple<int, int> GetMultipleValue()
{
return Tuple.Create(1,2);
}
두 값 한과 튜플 Item1
및 Item2
속성으로.
public (int sum, int count) GetMultipleValues() { return (1, 2); }
이 예에서 찍은 이에 우리의 문서 주제 예 .
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; }
}
async
방법으로 는 불가능합니다 . Tuple
갈 길입니다. ( out
하지만 동기 작업에서 매개 변수를 사용 합니다. 이러한 경우에는 실제로 유용합니다.)
여러 값을 반환하려는 경우 반환하려는 값이 포함 된 클래스 / 구조를 반환하거나 다음과 같이 매개 변수에 "out"키워드를 사용할 수 있습니다.
public void Foo(int input, out int output1, out string output2, out string errors) {
// set out parameters inside function
}
이전 포스터가 맞습니다. C # 메서드에서 여러 값을 반환 할 수 없습니다. 그러나 몇 가지 옵션이 있습니다.
여기의 장단점은 종종 파악하기가 어렵습니다. 구조체를 반환하는 경우 구조체는 값 형식이며 스택에 전달되므로 크기가 작아야합니다. 클래스의 인스턴스를 반환하면 문제를 피하기 위해 사용할 수있는 디자인 패턴이 있습니다 .C #은 참조로 개체를 전달하기 때문에 클래스 멤버를 수정할 수 있습니다 (VB에서와 같이 ByVal이 없기 때문에) ).
마지막으로 출력 매개 변수를 사용할 수 있지만 몇 개 (예 : 3 이하)의 매개 변수 만있는 경우 시나리오에이 사용을 제한합니다. 그렇지 않으면 유지 관리가 어려워집니다. 또한 출력 매개 변수를 사용하면 반환 값에 무언가를 추가해야 할 때마다 메서드 서명이 변경되어야하지만 구조체 또는 클래스 인스턴스를 반환하면 메서드 서명을 수정하지 않고 멤버를 추가 할 수 있기 때문에 민첩성을 저해 할 수 있습니다.
아키텍처 관점에서 키-값 쌍 또는 사전을 사용하지 않는 것이 좋습니다. 이 스타일의 코딩에는 메서드를 사용하는 코드에서 "비밀 지식"이 필요합니다. 키의 의미와 값의 의미를 미리 알고 있어야하며 내부 구현 작업을 수행하는 개발자가 사전 또는 KVP 작성 방식을 변경하면 전체 애플리케이션에서 장애 단계를 쉽게 작성할 수 있습니다.
Exception
반환하려는 두 번째 값이 첫 번째 값과 이질적인 경우 if를 던질 수 있습니다 .
클래스 인스턴스 를 반환 하거나 매개 변수를 사용 합니다 . 다음은 출력 매개 변수의 예입니다.
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
많은 방법이 있습니다. 그러나 새로운 객체 또는 구조 또는 이와 같은 것을 만들고 싶지 않으면 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");
}
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"
그러나 직렬화에주의,이 모든 문법 설탕입니다 - 실제 컴파일 된 코드에서이 될 것이다 Tuple<string, int>
(같은 허용 대답 당 과) Item1
및 Item2
대신 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}.");
자세한 내용은 여기를 참조하십시오 .
이를 수행하는 몇 가지 방법이 있습니다. ref
매개 변수 를 사용할 수 있습니다 .
int Foo(ref Bar bar) { }
이것은 함수에 대한 참조를 전달하여 함수가 호출 코드의 스택에서 객체를 수정할 수 있도록합니다. 이것은 기술적으로 "반환 된"값이 아니지만 함수가 비슷한 것을 수행하도록하는 방법입니다. 위의 코드에서 함수는 int
and (잠재적으로) 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 이상에서는 사용자 정의 클래스 또는 구조체가 필요합니다.
기본 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
.
델리게이트를받는 메소드는 호출자에게 여러 값을 제공 할 수 있습니다. 이것은 내 대답 에서 빌려 왔으며 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 ++ 질문 에도이 솔루션을 입력했습니다.
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;
}
그것을하는 방법 :
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" };
}
yield return "value1"; yield return "value2";
명시 적으로 새 것을 만들 필요가없는 as를 사용하지 않는 이유 는 string[]
무엇입니까?
배열 유형에 대한 빠른 답변은 다음을 반환합니다.
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[1];