Как указать метод выбора списка? - PullRequest
2 голосов
/ 02 декабря 2010

У меня есть метод, который вычисляет список.В определенных точках алгоритма необходимо выбрать один элемент из списка.На самом деле не имеет значения, какой элемент выбран, но я бы хотел оставить решение за пользователем.

Сейчас я добавил метод расширения IList<T>.Random(), который просто принимает случайныйэлемент..First() сработало бы одинаково хорошо.Предположим, я хочу позволить пользователю выбрать, какой метод используется, или, может быть, совершенно другой метод, как бы это выглядело?

Я думал об использовании enum с ограниченными параметрами, а затем я мог обернуть каждый из них.вызывает коммутатор и вызывает соответствующую функцию. Но, возможно, какая-то лямбда-функция будет более уместной ?

Этот метод необходимо использовать в двух разных местах: один раз на List<char> и один раз наList<string>.Я хочу использовать один и тот же метод для обоих.


Это не приложение с графическим интерфейсом.Я пытаюсь решить, как разработать 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 (), тогда я мог бы сделать его универсальным ... но я надеялся сохранить его на уровне класса для повторного использования.Не хочу больше передавать аргументы функции, если я могу ей помочь.

Редактировать: полный исходный код

Ответы [ 4 ]

2 голосов
/ 02 декабря 2010

как насчет этого:


    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 голос
/ 02 декабря 2010

Вот очень простой пример, который я собрал, используя универсальный метод, который принимает 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);
        }
    }
}

Если вы хотите ограничить выбор, который есть у пользователя, вы можете следовать по маршруту enum и сделать этот метод закрытым, а затем иметьспособ преобразования перечисления в соответствующий делегат селектора для передачи в базовый закрытый метод.

0 голосов
/ 03 декабря 2010

Это работает для символов и строк. Не проверял с другими типами. Построил это до того, как увидел код Ральфа, который практически не изменился.

Код 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); 
}
0 голосов
/ 02 декабря 2010
public Func<IList<object>, object> SelectElement = list => list.First();

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

Я могу заставить анонимный метод работать с объектами, избегая, таким образом, обобщений, а затем добавить вспомогательный метод, который я и буду использовать для его вызова.Немного некрасиво, но, кажется, работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...