【问题标题】:Assign values of array to separate variables in one line将数组的值分配给一行中的单独变量
【发布时间】:2009-09-14 15:09:00
【问题描述】:

我可以在 C# 中将数组中的每个值分配给单独的变量吗?这是我想要的 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”的事实是任意的。实际上它可以返回任意两个值,它们甚至不必是字符串。

【问题讨论】:

  • 哇,丑陋而令人困惑。提醒我上次约会。
  • @Will:真的吗?我认为它很好而且简洁,同时仍然清晰易读。我比较喜欢python中的特性,经常使用。
  • 从 C# 的角度来看,绝对是。看起来您正在将单个数组的引用分配给两个不同的变量......比如 str1 = new string[] {"one","two"}; str2 = str1;所以它立即让 C# 开发人员感到困惑。丑陋的部分只是为了让我能开个玩笑。
  • 也许如果 C# 是你唯一的语言,那么是的,我想它看起来有点难看。也许你应该考虑拓宽你的视野?不管怎样,虽然我从来没有用过 ruby​​ 开发,但我已经用 python 做了很多,所以这个任务对我来说一点也不新鲜。它看起来像一个简单的元组创建和解包(也称为元组分配)。尽管 Ruby 显然使用方括号 [] 而不是像 python 那样的 parens (),但它在语法上是相同的。基于@Sarah 的 cmets,我希望它的功能相同。
  • 我认为 Will 指的是示例的命令行部分。没有做过 Ruby,我自己做了一个双重考虑。作业本身简洁、清晰、易读。

标签: c# arrays string initialization declaration


【解决方案1】:

这在 C# 中是不可能的。

我能想到的最接近的事情是在索引的同一行中使用初始化

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

【讨论】:

  • 这就是 ruby​​ 在幕后所做的; @Sarah 想做的事情基本上是语法糖。
  • 我称之为句法 s-something。 Ruby是否隐藏了原语和引用类型的内存分配之间的差异???
  • Ruby 是一种脚本语言。没有原始类型;它们都在堆上——引用类型。
【解决方案2】:

更新:在 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 作为 缩写:

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

您还可以使用解构函数解构为现有变量 作业:

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

解构不仅仅适用于元组。任何类型都可以解构, 只要它有一个(实例或扩展)解构方法 形式:

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

out 参数构成从 解构。

(为什么它使用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 的解决方案那样显式声明变量类型。

缺点是你最终会得到额外的代码块,但我认为这是值得的。您可以使用代码 sn-ps 以避免手动输入大括号等。

我知道这是一个 7 年前的问题,但不久前我需要这样一个解决方案 - 轻松为传递给方法的数组元素命名(不,使用类/结构而不是数组是不切实际的,因为对于相同的数组,我可能需要在不同的方法中使用不同的元素名称),不幸的是我最终得到了这样的代码:

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

现在我可以写了(事实上,我现在已经重构了其中一种方法!):

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

我的解决方案类似于 F# 中的模式匹配,我受到这个答案的启发:https://stackoverflow.com/a/2321922/6659843

【讨论】:

    【解决方案3】:

    现实世界的用例是提供一种从函数返回多个值的便捷方式。所以它是一个 Ruby 函数,它在数组中返回固定数量的值,调用者希望它们在两个单独的变量中。这是该功能最有意义的地方:

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

    要在 C# 中表达这一点,您可以在方法定义中用 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&lt;string, string&gt;。这将是对语言的非破坏性更改,因为var 的当前合法用途非常严格,因此上述“多重声明”语法尚无有效用途。

    【讨论】:

      【解决方案4】:

      您可以在一行中完成,但不能作为一个语句。

      例如:

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

      Python 和 ruby​​ 支持您尝试执行的任务; C# 没有。

      【讨论】:

        【解决方案5】:

        你可以在 C# 中做到这一点

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

        或者你可以像这样花哨

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

        【讨论】:

          【解决方案6】:

          您现在可以将命名元组与C# 7 一起使用。

          {
            (string part1, string part2) = Deconstruct(new string[]{"hey","now"});
          }
          
          public (string, string) Deconstruct(string[] parts)
          {
             return (parts[0], parts[1]);
          }
          

          【讨论】:

            【解决方案7】:

            我不确定我想要的是不是 可以在 C# 中使用。

            不是。

            【讨论】:

              【解决方案8】:

              不,但你可以初始化一个字符串数组:

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

              虽然这对你来说可能不太有用。坦率地说,将它们放在两条线上并不难:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-10-31
                • 1970-01-01
                • 2014-03-27
                相关资源
                最近更新 更多