私はこの質問のC ++バージョンを読みましたが、本当に理解していませんでした。
誰かがそれを実行できるかどうか、またその方法を明確に説明できますか?
私はこの質問のC ++バージョンを読みましたが、本当に理解していませんでした。
誰かがそれを実行できるかどうか、またその方法を明確に説明できますか?
回答:
C#7以降では、この回答を参照してください。
以前のバージョンでは、.NET 4.0+のタプルを使用できます。
例えば:
public Tuple<int, int> GetMultipleValue()
{
return Tuple.Create(1,2);
}
2つの値を持つタプルにはItem1
およびItem2
プロパティがあります。
public (int sum, int count) GetMultipleValues() { return (1, 2); }
この例では、から撮影されたこの上で私たちのドキュメントのトピックの例。
C#7がリリースされたので、新しく組み込まれたタプル構文を使用できます
(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」などではありません)。これは、シグニチャーまたはreturnメソッドに名前を追加することで実行できます。
(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
このリンクをチェックして、何ができるかについての例を見てください:)
3つの異なる方法を使用できます
1. ref / outパラメータ
refを使用:
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はありません) )。
最後に、出力パラメーターを使用できますが、パラメーターの数が2つ(3以下など)しかない場合は、これをシナリオの使用に制限します。そうしないと、醜く、維持が難しくなります。また、戻り値に何かを追加する必要があるたびにメソッドシグネチャを変更する必要があるため、出力パラメーターの使用は俊敏性を阻害する可能性がありますが、構造体またはクラスインスタンスを返すと、メソッドシグネチャを変更せずにメンバーを追加できます。
アーキテクチャの観点から、キーと値のペアや辞書を使用しないことをお勧めします。このスタイルのコーディングには、メソッドを使用するコードに「秘密の知識」が必要であることがわかりました。キーがどうなるか、値が何を意味するのかを事前に知っておく必要があります。内部実装に取り組んでいる開発者がディクショナリまたはKVPの作成方法を変更すると、アプリケーション全体で簡単に障害カスケードが発生する可能性があります。
Exception
、返したい2番目の値が最初の値と分離している場合にもスローできます。たとえば、ある種の成功した値またはある種の失敗した値を返したい場合などです。
クラスインスタンスを返すか、outパラメータを使用します。以下は、outパラメータの例です。
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
andのItem2
代わりにfoo
andになりbar
ます。つまり、シリアル化(または逆シリアル化)では、代わりにそれらのプロパティ名が使用されます。
したがって、シリアライゼーションの場合、レコードクラスを宣言し、代わりにそれを返します。
また、C#7では、out
パラメーターの構文が改善されています。out
これでインラインを宣言できるようになりました。これは一部のコンテキストに適しています。
if(int.TryParse("123", out int result)) {
// Do something with result
}
ただし、ほとんどの場合、これは独自の関数ではなく、.NET独自のライブラリで使用します。
一部の回答では、出力パラメーターの使用を提案していますが、非同期メソッドでは機能しないため、これを使用しないことをお勧めします。詳細については、 こちらをご覧ください。
他の回答ではタプルの使用について述べましたが、私もお勧めしますが、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を(場合によっては)変更して返しbar
ます。
別の同様のアプローチは、out
パラメーターを使用することです。out
パラメータは同じですref
追加、コンパイラ施行規則を持つパラメータ。このルールではout
、関数にパラメーターを渡す場合、関数は戻る前に値を設定する必要があります。そのルールを除けば、out
パラメーターはパラメーターと同じように機能しref
ます。
最後のアプローチ(そしてほとんどの場合に最適)は、両方の値をカプセル化する型を作成し、関数がそれを返すことを可能にすることです。
class FooBar
{
public int i { get; set; }
public Bar b { get; set; }
}
FooBar Foo(Bar bar) { }
この最終的なアプローチは、シンプルで読みやすく、理解しやすくなっています。
いいえ、C#の関数から複数の値を返すことはできません(C#7より前のバージョンの場合)。少なくともPythonで実行できる方法ではできません。
ただし、いくつかの選択肢があります。
必要な複数の値を含むオブジェクト型の配列を返すことができます。
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では、タプルの組み込みサポートを使用して、これを簡単に処理できます。
それまでの間、2つのオプションがあります。
まず、refまたはoutパラメーターを使用してパラメーターに値を割り当て、呼び出し元のルーチンに返すことができます。
これは次のようになります。
void myFunction(ref int setMe, out int youMustSetMe);
次に、戻り値を構造体またはクラスにラップして、それらをその構造体のメンバーとして渡すことができます。KeyValuePairは2で適切に機能します。2を超える場合は、カスタムクラスまたは構造体が必要になります。
基本的なTwo
方法は次のとおりです。
1)out
パラメータとしての ' 'の使用
4.0バージョンとマイナーバージョンの両方で '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
注: タプルの使用は、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
(ビデオからの不完全な例)
動的オブジェクトを使用できます。タプルより読みやすいと思います。
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.32 ns):
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.40 ns:
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->ナノ秒
リファレンス:multiple-return-values。
あなたはこれを試すことができます
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
yield return "value1"; yield return "value2";
明示的に新しいものを作成する必要がないので、なぜ使用しないの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];