如何分隔 C# 元组值以匹配方法参数

How to separate C# tuple values to match method arguments

我想知道是否可以 'spread' 元组的值以正确匹配方法参数的方式。

例如:

public (int, object) GetTuple() {
   return (5, null);
}

public void ReceiveMultipleArguments(int a, object b) { ... }

ReceiveMultipleArguments方法的调用是这样的:

ReceiveMultipleArguments(GetTuple());

将导致此错误:

CS7036: There is no argument given that corresponds to the required formal parameter 'b' of 'Method1(int, object)'

可能的解决方案是手动解构元组,然后将每个值作为方法参数提供,但是有没有办法让它更短,例如 javascript 中存在的 spread operator

也许这对你有帮助:

static void Main(string[] args)
{
    ReceiveMultipleArguments(GetTuple());
    Console.WriteLine();
}

public static (int, object) GetTuple()
{
    return (5, null);
}

public static void ReceiveMultipleArguments((int, object) p)
{
    Console.WriteLine(p.Item1);
    Console.WriteLine(p.Item2);
}

C# 是强类型语言,所以你不能传递元组(它有自己的 class ValueTuple class)。

因此您可以只为方法定义重载:

public void Test()
{
    ReceiveMultipleArguments(GetTuple());
}

public (int, object) GetTuple()
{
    return (5, null);
}

public void ReceiveMultipleArguments((int a, object b) @params) => ReceiveMultipleArguments(@params.a, @params.b);
public void ReceiveMultipleArguments(int a, object b) { ... }

您可以更改方法的签名以支持 paramsobject 个元素。然后你可以将元组解压成单独的元素并将其用作参数。

public void Main()
{
    var tuple = GetTuple();
    var items = UnpackTuple(tuple).ToArray();

    DoSomethingWith(items);
}

public void DoSomethingWith(params object[] data)
{
    foreach (var d in data)
    {
        Console.WriteLine(d);
    }
}

public IEnumerable<object> UnpackTuple(ITuple tuple)
{
    for (var index = 0; index < tuple.Length; index++)
    {
        yield return tuple[index];
    }
}

public ITuple GetTuple()
{
    return Tuple.Create(5, "second", 2.489, 'G');
}

但是,如果您需要在程序中移动元组,我强烈建议您放弃元组。根据经验,我已经看到这将导致代码库混乱,难以理解和更改。

相反,为您的元组定义 classes。比方说你需要传递一个对象,比方说一个苹果,以及有多少苹果的计数到某个方法中。 class 可以是通用的 class 例如:

public class CountOf<T>
{
    public CountOf(T value, int count)
    {
        this.Value = value;
        this.Count = count;
    }

    public T Value { get; }

    public int Count { get; set; }
}

或非泛型,如:

public class CountedObject
{
    public CountedObject(object obj, int count)
    {
        this.Object = obj;
        this.Count = count;
    }

    public object Object { get; }

    public int Count { get; set; }
}

用例:

public void Main()
{
    var apple = new Apple();
    
    var countedApples = new CountOf<Apple>(apple, 10);
    DoSomethingWith(countedApples);
    
    var countedObject = new CountedObject(apple, 10);
    DoSomethingWith(countedObject);
}

public void DoSomethingWith(CountOf<Apple> countedApples)
{
    // do something here
}

public void DoSomethingWith(CountedObject countedObject)
{
    // do something here
}

public class Apple { }

public class CountOf<T>
{
    public CountOf(T value, int count)
    {
        this.Value = value;
        this.Count = count;
    }

    public T Value { get; }

    public int Count { get; set; }
}

public class CountedObject
{
    public CountedObject(object obj, int count)
    {
        this.Object = obj;
        this.Count = count;
    }

    public object Object { get; }

    public int Count { get; set; }
}