C# 优雅地将列表和对象作为参数传递

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18066489/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:12:37  来源:igfitidea点击:

Elegantly passing lists and objects as params

c#

提问by ean5533

In C#, one can use the paramskeyword to specify an arbitrary number of typed parameters to a method:

在 C# 中,可以使用params关键字为方法指定任意数量的类型参数:

public void DoStuff(params Foo[] foos) {...}

public void OtherStuff {
    DoStuff(foo1);
    DoStuff(foo2, foo3);
}

If you already have a list of objects, you can turn it into an array to pass to this method:

如果你已经有一个对象列表,你可以把它变成一个数组来传递给这个方法:

DoStuff(fooList.ToArray());

However, is there any elegant way to mix-n-match? That is, to pass in multiple objects and lists of objects and have the results flattened into one list or array for you? Ideally, I would like to be able to call my method like this:

但是,有什么优雅的混合搭配方式吗?也就是说,要传入多个对象和对象列表,并将结果展平到一个列表或数组中?理想情况下,我希望能够像这样调用我的方法:

DoStuff(fooList, foo1, foo2, anotherFooList, ...);

As of right now, the only way I know how to do this is to pre-process everything into one list, and I don't know of any way to do this generically.

截至目前,我知道如何执行此操作的唯一方法是将所有内容预处理为一个列表,而我不知道有任何一般方法可以执行此操作。

Edit:To be clear, I'm not married to the paramskeyword, it's just a related mechanism that helped me explain what I wanted to do. I'm quite happy with any solution that looks clean and flattens everything into a single list.

编辑:明确地说,我并没有与params关键字结婚,它只是一个相关机制,帮助我解释了我想做的事情。我对任何看起来干净并将所有内容都压平到一个列表中的解决方案感到非常满意。

采纳答案by Lee

You could create a class with implict conversions to wrap a single element and a list:

您可以创建一个带有隐式转换的类来包装单个元素和一个列表:

public class ParamsWrapper<T> : IEnumerable<T>
{
    private readonly IEnumerable<T> seq;

    public ParamsWrapper(IEnumerable<T> seq)
    {
        this.seq = seq;
    }

    public static implicit operator ParamsWrapper<T>(T instance)
    {
        return new ParamsWrapper<T>(new[] { instance });
    }

    public static implicit operator ParamsWrapper<T>(List<T> seq)
    {
        return new ParamsWrapper<T>(seq);
    }

    public IEnumerator<T> GetEnumerator()
    {
        return this.seq.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

then you can change your DoStuffmethod to:

那么您可以将您的DoStuff方法更改为:

private static void DoStuff(params ParamsWrapper<Foo>[] foos)
{
    Foo[] all = foos.SelectMany(f => f).ToArray();
    //
}

回答by Alexei Levenkov

You can use Enumerable.Concatto join multiple lists and items like:

您可以使用Enumerable.Concat加入多个列表和项目,例如:

 DoStuff(fooList
       .Concat(Enumerable.Repeat(foo1,1))
       .Concat(Enumerable.Repeat(foo2,1))
       .Concat(Enumerable.Repeat(anotherFooList))
       .ToArray();

Note: there are likely much more readable ways to achieve whatever you are trying to do. Even passing IEnumerable<Foo>is more readable.

注意:可能有更多可读的方法来实现您想要做的任何事情。甚至通过IEnumerable<Foo>也更具可读性。

回答by devuxer

You can't quite do what you're trying to do, but with an extension method, you could get pretty close:

你不能完全做你想做的事情,但使用扩展方法,你可以非常接近:

void Main()
{
    var singleFoo = new Foo();
    var multipleFoos = new[] { new Foo(), new Foo(), new Foo() };
    var count = DoStuffWithFoos(singleFoo.Listify(), multipleFoos).Count();
    Console.WriteLine("Total Foos: " + count.ToString());
}

public IEnumerable<Foo> DoStuffWithFoos(params IEnumerable<Foo>[] fooLists)
{
    return fooLists.SelectMany(fl => fl); // this flattens all your fooLists into
                                          // a single list of Foos
}

public class Foo { }

public static class ExtensionMethods
{
    public static IEnumerable<Foo> Listify(this Foo foo)
    {
        yield return foo;
    }
}

回答by konkked

you could make separate methods to load the objects into the same collection, not that elegant but it will work, and the logic is really easy to follow, and not very hard to implement.

您可以使用不同的方法将对象加载到同一个集合中,虽然不是那么优雅,但它会起作用,而且逻辑非常容易遵循,而且实现起来并不难。

public class Flattener<T> : IEnumerable<T>
{
    private List<T> _collection = new List<T> ( );
    public void Add ( params T [ ] list )
    {
        _collection.AddRange ( list );
    }

    public void Add ( params IEnumerable<T> [ ] lists )
    {
        foreach ( var list in lists )
            _collection.AddRange ( list );
    }

    public T Result
    {
        get
        {
            return _collection.ToArray();
        }
    }

    public IEnumerator<T> GetEnumerator ( )
    {
        return _collection.GetEnumerator ( );
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ( )
    {
        return GetEnumerator ( );
    }
}


Flattener<Foo> foos = new Flattener();
foos.Add(fooList, fooList2, fooList3,...);
foos.Add(foo1,foo2,foo3,...);
DoStuff(foos.Result);