如何指定列表选择方法?

时间:2010-12-02 19:17:15

标签: c# api design-patterns

我有一个计算列表的方法。在算法中的某些点处,需要选择列表中的单个元素。选择哪个元素并不重要,但我想让用户自行决定。

现在,我添加了一个扩展方法IList<T>.Random(),它只是一个随机元素。 .First()也同样有效。假设我想让用户选择使用哪种方法,或者可能采用完全不同的方法,那会是什么样的?

我正在考虑使用有限选项的枚举,然后我可以将每个调用包装在一个开关中并调用相应的函数。 但是some sort of lambda function可能更合适

此方法需要在两个不同的位置使用,一次在List<char>上,一次在List<string>上。我想对两者使用相同的方法。


这不是GUI应用程序。我正在尝试决定如何设计API。

具体来说,我希望有一个像

这样的字段
public Func<IList<T>, T> SelectElement = list => list.First();

然后将在方法中使用

 public string Reverse(string pattern, IList<object> args = null, IDictionary<string, object> kwargs = null)

但是通用字段是不可能的。所以我正在寻找替代解决方案。一种方法是将SelectElement方法作为Reverse()的参数,然后我可以使它成为通用的...但我希望将它保持在类级别以便重用。如果我可以提供帮助,不要再向该函数传递args。

修改: full source code

4 个答案:

答案 0 :(得分:2)

怎么样:


    public class MyClass
    {
        public static class C<T>
        {
            public static Func<IList<T>, T> SelectElement;
        }

        public int Test(IList<int> list)
        {
            return C<int>.SelectElement(list);
        }
    }

    static class Program
    {
        static void Main(string[] args)
        {
            MyClass.C<char>.SelectElement = xs => xs.First();
            MyClass.C<int>.SelectElement = xs => xs.First();

            var list = new List<int>(new int[] { 1, 2, 3 });

            var c = new MyClass();

            var v = c.Test(list);
            Console.WriteLine(v);
        }
    }

答案 1 :(得分:1)

这是我使用泛型方法放在一起的一个非常基本的示例,该方法接受Func<IEnumerable<T>, T>从列表中选择项目然后返回结果。我已经做了一些如何调用它的例子:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            //Simple list.
            var list = new List<int> { 1, 2, 3, 4 };

            // Try it with first
            var result = DoItemSelect(list, Enumerable.First);
            Console.WriteLine(result);

            // Try it with last
            result = DoItemSelect(list, Enumerable.Last);
            Console.WriteLine(result);

            // Try it with ElementAt for the second item (index 1) in the list.
            result = DoItemSelect(list, enumerable => enumerable.ElementAt(1));
            Console.WriteLine(result);
        }

        public static T DoItemSelect<T>(IEnumerable<T> enumerable, Func<IEnumerable<T>, T> selector)
        {
            // You can do whatever you method does here, selector is the user specified func for
            // how to select from the enumerable.  Here I just return the result of selector directly.
            return selector(enumerable);
        }
    }
}

如果要限制用户的选择,可以遵循枚举的路径并使此方法成为私有方法,然后有办法将枚举转换为适当的选择器委托以传递给底层私有方法。

答案 2 :(得分:0)

public Func<IList<object>, object> SelectElement = list => list.First();

private T _S<T>(IEnumerable<T> list)
{
    return (T)SelectElement(list.Cast<object>().ToList());
}

我可以让匿名方法处理对象,从而避免使用泛型,然后添加一个帮助方法,这是我实际用来调用它的方法。有点难看,但似乎有效。

答案 3 :(得分:0)

这适用于字符和字符串。没有测试过其他类型。在我看到Ralph的代码之前构建了它,这几乎是相同的。

LINQPad代码:

void Main()
{
    var chars = new List<char>(); 
    var strings = new List<string>(); 

    chars.AddRange(new char[] {'1','2','4','7','8','3'});
    strings.AddRange(new string[] {"01","02","09","12","28","52"}); 

    chars.Dump(); 
    strings.Dump(); 

    Func<IList<object>, string> SelectFirst = ( list ) 
        => list.First().ToString();
    Func<IList<object>, string> SelectLast = ( list ) 
        => list.Last().ToString();
    Func<IList<object>, string> SelectRandom = ( list ) 
        => list.ElementAt( new Random().Next(0, list.Count())).ToString(); 

    SelectBy(SelectFirst, strings.Cast<object>().ToList()).Dump(); 
    SelectBy(SelectFirst, chars.Cast<object>().ToList()).Dump(); 

    SelectBy(SelectLast, strings.Cast<object>().ToList()).Dump(); 
    SelectBy(SelectLast, chars.Cast<object>().ToList()).Dump(); 

    SelectBy(SelectRandom, strings.Cast<object>().ToList()).Dump(); 
    SelectBy(SelectRandom, chars.Cast<object>().ToList()).Dump(); 
}

private string SelectBy(Func<IList<object>, string> func, IList<object> list)
{   
    return func(list); 
}