web-dev-qa-db-ja.com

配列の値を1行で別々の変数に割り当てます

配列の各値をC#の1行で別々の変数に割り当てることはできますか?これがRuby私が欲しいもののコードの例です:

irb(main):001:0> str1, str2 = ["hey", "now"]
=> ["hey", "now"]
irb(main):002:0> str1
=> "hey"
irb(main):003:0> str2
=> "now"

私が望んでいることがC#で可能かどうかはわかりません。

編集:文字列「hey」と「now」を変数に割り当てることを提案している人のために、それは私が望むものではありません。次のことを想像してみてください。

irb(main):004:0> val1, val2 = get_two_values()
=> ["hey", "now"]
irb(main):005:0> val1
=> "hey"
irb(main):006:0> val2
=> "now"

さて、メソッドget_two_values返される文字列「hey」と「now」は任意です。実際、2つの値を返す可能性があり、文字列である必要はありません。

23
Sarah Vessels

これはC#では不可能です。

私が考えることができる最も近いことは、インデックスと同じ行で初期化を使用することです

strArr = new string[]{"foo","bar"};
string str1 = strArr[0], str2 = strArr[1];
16
JaredPar

更新:C#7では、タプルを使用して一度に複数の変数を簡単に割り当てることができます。配列要素を変数に割り当てるには、適切なDeconstruct()拡張メソッドを作成する必要があります。

タプルを消費する別の方法は、タプルを分解することです。分解宣言は、タプル(または他の値)をその部分に分割し、それらの部分を新しい変数に個別に割り当てるための構文です。

(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
WriteLine($"found {first} {last}.");

分解宣言では、宣言された個々の変数にvarを使用できます。

(var first, var middle, var last) = LookupName(id1); // var inside

または、省略形として括弧の外に単一の変数を配置することもできます。

var (first, middle, last) = LookupName(id1); // var outside

分解割り当てを使用して、既存の変数に分解することもできます。

(first, middle, last) = LookupName(id2); // deconstructing assignment

脱構築はタプルだけのものではありません。次の形式の(インスタンスまたは拡張)deconstructorメソッドがある限り、任意の型を分解できます。

public void Deconstruct(out T1 x1, ..., out Tn xn) { ... }

Outパラメータは、分解の結果として生じる値を構成します。

(タプルを返す代わりにパラメーターを使用するのはなぜですか?これは、異なる数の値に対して複数のオーバーロードを持つことができるようにするためです)。

class Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y) { X = x; Y = y; }
    public void Deconstruct(out int x, out int y) { x = X; y = Y; }
}

(var myX, var myY) = GetPoint(); // calls Deconstruct(out myX, out myY);

このようにコンストラクターとデコンストラクターを「対称」にするのが一般的なパターンです。 https://blogs.msdn.Microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/


古い答え:

実際、次のような拡張メソッドを使用することで、C#で同様の機能を実現できます(注:引数が有効かどうかのチェックは含まれていません)。

public static void Match<T>(this IList<T> collection, Action<T,T> block)
{
    block(collection[0], collection[1]);
}
public static void Match<T>(this IList<T> collection, Action<T,T,T> block)
{
    block(collection[0], collection[1], collection[2]);
}
//...

そして、あなたはこれらをこのように使うことができます:

new[] { "hey", "now" }.Match((str1, str2) =>
{
    Console.WriteLine(str1);
    Console.WriteLine(str2);
});

関数からの戻り値が必要な場合は、次のオーバーロードが機能します。

public static R Match<T,R>(this IList<T> collection, Func<T, T, R> block)
{
    return block(collection[0], collection[1]);
}

private string NewMethod1()
{   
    return new[] { "hey", "now" }.Match((str1, str2) =>
    {
        return str1 + str2;
    });
}

この方法では:

  • JaredParなどによって提案されたソリューションのように配列名を繰り返す必要がなくなります。 「変数」のリストは読みやすいです。

  • Daniel Earwickerのソリューションのように、変数の型を明示的に宣言する必要はありません。

欠点は、追加のコードブロックが必要になることですが、それだけの価値があると思います。中括弧などを手動で入力しないようにするために、コードスニペットを使用できます。

私はそれが7年前の質問であることを知っていますが、それほど昔にはそのような解決策が必要でした-メソッドに渡される配列要素に簡単に名前を付ける(いいえ、配列の代わりにクラス/構造体を使用することは実用的ではありませんでしたさまざまなメソッドでさまざまな要素名が必要になる可能性があります)、残念ながら、次のようなコードになりました。

var A = points[0];
var A2 = points[1];
var B = points[2];
var C2 = points[3];
var C = points[4];

今、私は書くことができました(実際、私は今それらのメソッドの1つをリファクタリングしました!):

points.Match((A, A2, B, C2, C) => {...});

私のソリューションはF#のパターンマッチングに似ており、この回答に触発されました: https://stackoverflow.com/a/2321922/665984

13
user1414213562

これの実際のユースケースは、関数から複数の値を返す便利な方法を提供することです。したがって、配列内の固定数の値を返すのはRuby関数であり、呼び出し元は2つの別々の変数でそれらを必要とします。これがこの機能が最も理にかなっている場所です。

first_name, last_name = get_info() // always returns an array of length 2

これをC#で表現するには、メソッド定義で2つのパラメーターをoutでマークし、voidを返します。

public static void GetInfo(out string firstName, out string lastName)
{
    // assign to firstName and lastName, instead of trying to return them.
}

そしてそれを呼ぶために:

string firstName, lastName;
SomeClass.GetInfo(out firstName, out lastName);

それはそれほどいいことではありません。うまくいけば、C#の将来のバージョンでこれが可能になるでしょう:

var firstName, lastName = SomeClass.GetInfo();

これを有効にするには、GetInfoメソッドはTuple<string, string>を返します。 varの現在の合法的な使用は非常に制限されているため、これは言語に対する重大な変更ではなく、上記の「複数宣言」構文の有効な使用法はまだありません。

4

あなたはC#でこれを行うことができます

string str1 = "hey", str2 = "now";

またはあなたはこのように空想することができます

        int x, y;
        int[] arr = new int[] { x = 1, y = 2 };
2
ja72

1行で実行できますが、1つのステートメントとして実行することはできません。

例えば:

int str1 = "hey"; int str2 = "now";

PythonとRubyは、実行しようとしている割り当てをサポートしていますが、C#はサポートしていません。

2
Randolpho

C#7 で名前付きタプルを使用できるようになりました。

{
  (string part1, string part2) = Deconstruct(new string[]{"hey","now"});
}

public (string, string) Deconstruct(string[] parts)
{
   return (parts[0], parts[1]);
}
1
Illuminati

私が望んでいることがC#で可能かどうかはわかりません。

そうではありません。

1
sepp2k

いいえ。ただし、文字列の配列を初期化できます。

string[] strings = new string[] {"hey", "now"};

それはおそらくあなたにとってあまり役に立たないでしょうが。率直に言って、それらを2行に並べることは難しくありません。

string str1 = "hey";
string str2 = "now";
0
Ron Warholic