C # Передача массива Funcк методу - PullRequest
4 голосов
/ 11 марта 2011

Мой первый (и действительно ужасный пост) ниже.

Я пытаюсь сделать полный пример того, что я хочу получить.Я надеюсь, что это будет объяснено немного лучше.

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Boy> boys = new List<Boy>();
            boys.Add(new Boy("Jhon", 7));
            boys.Add(new Boy("Oscar", 6));
            boys.Add(new Boy("Oscar", 7));
            boys.Add(new Boy("Peter", 5));
            ClassRoom myClass = new ClassRoom(boys);

            Console.WriteLine(myClass.ByName("Oscar").Count);  // Prints 2
            Console.WriteLine(myClass.ByYearsOld(7).Count);  // Prints 2

            // This has errors...................
            // But this is as I would like to call my BySomeConditions method....
            Console.WriteLine(  // It should print 1
                                myClass.BySomeConditions([myClass.ByName("Oscar"),
                                                          myClass.ByYearsOld(7)]
                                                        )
                             );
            Console.ReadKey();
        }





        class ClassRoom
        {
            private List<Boy> students;

            public ClassRoom(List<Boy> students)
            {
                this.students = students;
            }

            public List<Boy> ByName(string name)
            {
                return students.FindAll(x => x.Name == name);
            }
            public List<Boy> ByYearsOld(int yearsOld)
            {
                return students.FindAll(x => x.YearsOld == yearsOld);
            }

            // This has ERRORS.......................
            public List<Boy> BySomeConditions(params Func<X, List<Boy>>[] conditions)
            {
                IEnumerable<Boy> result = students;                
                foreach (var condition in conditions) {
                    // I want it ONLY be called with existent functions (ByName and/or ByYearsOld)
                    result = result.Intersect(condition(this));  
                }
            }
        }


        class Boy
        {
            public string Name { get; set; }
            public int YearsOld { get; set; }
            public Boy(string name, int yearsOld)
            {
                Name = name;
                YearsOld = yearsOld;
            }
        }
    }
}

============== Первый пост ===================== Здравствуйте,

У меня есть класс с методами:

public class X
{
    private readonly List<string> myList;

    public X(List<string> paramList) // string is really an object
    {
         myList = paramList;
    }

    // Now I want this...
    public List<string> CheckConditions(params Func<T, List<string>>[] conditions)
    {
         var result = myList;
         foreach (Func<T, List<string>> condition in conditions)
         {
               result = result.Intersect(condition(T));
         }
    }

    public List<string> check1(string S)
    {
         return myList.FindAll(x => x.FieldS == S);
    }
    public List<string> check1(int I)
    {
         return myList.FindAll(x => x.FieldI == I);
    }
}

Извините, если есть какая-то ошибка, я написал с нуля визбегайте сложных реальных случаев.

Я хочу назвать мои методы так:

   X.check1("Jhon");

или

   X.check2(12);

или ( это цельмой вопрос ):

   X.CheckConditions(X.check1("Jhon"), X.chek2(12));

Спасибо и извините за мой плохой пример ...

Ответы [ 5 ]

3 голосов
/ 11 марта 2011

Непонятно, откуда ваш T.

Соответствует ли это вашим требованиям?

public class X<T>
{
  private List<T> myList;

  public List<T> CheckConditions(params Func<T, bool>[] conditions)
  {
    IEnumerable<T> query = myList;
    foreach (Func<T, bool> condition in conditions)
    {
      query = query.Where(condition);
    }
    return query.ToList();
  }
}

Затем позже:

List<T> result = X.CheckConditions(
  z => z.FieldS == "Jhon",
  z => z.FieldI == 12
);
2 голосов
/ 11 марта 2011

Вам нужно изменить сигнатуру метода CheckConditions, она принимает переменное число List<string>, а не функции.

public List<string> CheckConditions(params List<string>[] lists)

Тип возврата check1 равен List<string>, поэтомуэто должен быть тип параметра, который CheckConditions принимает.

1 голос
/ 11 марта 2011

Нет причин делать это универсальным, вы знаете, что хотите работать с текущим экземпляром X (поэтому передайте this вместо параметра типа T).Вам нужно очистить несколько вещей, чтобы заставить его скомпилироваться (верните result и сделайте тип result и вызов Intersect совместимым).Вы можете определить это так:

public List<string> CheckConditions(params Func<X, List<string>>[] conditions)
{
     IEnumerable<string> result = myList;
     foreach (var condition in conditions)
     {
           result = result.Intersect(condition(this));
     }

     return result.ToList();
}

Муравей, а затем назовите это так:

xInstance.CheckConditions(x => x.check1("JHon"), x => x.check1(12));

Все это говорит, я не уверен, почему вы просто не обойдетерезультаты этих функций, вместо передачи фактических функций:

public List<string> CheckConditions(params List<string>[] conditions)
{
     IEnumerable<string> result = myList;
     foreach (var condition in conditions)
     {
           result = result.Intersect(condition);
     }

     return result.ToList();
}

Затем вызывайте его, как в вашем примере, вместо передачи лямбда-выражений.

0 голосов
/ 11 марта 2011

Вы можете переписать свою функцию так:

// Now I want this...
    public List<string> CheckConditions(params Func<T, List<string>>[] conditions)
    {
         var result = myList;
         foreach (Func<T, List<string>> condition in conditions)
         {
               result = result.Intersect(condition(T));
         }
    }

тогда ваш звонок будет X.CheckConditions(()=>X.check1("Jhon"), ()=>X.chek2(12));

и вам нужно предоставить экземпляр для x (поскольку методы являются методами экземпляра, а не статическими)

В вашем примере вы передаете T в качестве аргумента функтору, но T является аргументом типа som, который нельзя передать в качестве аргумента методу. Вы хотели передать значение?

Это требует разъяснения, почему вы хотели бы сделать это. Возможно, если вы предоставите подробную информацию о том, что вы пытаетесь выполнить (в отличие от того, как), то вы могли бы найти лучшее решение своей проблемы.

0 голосов
/ 11 марта 2011

Что вы передаете на

X.CheckConditions

- это не ссылка на функции, а возвращаемое значение их вызова.

Теперь, если вы передадите ссылку на функцию - она ​​не будет иметь параметров, если вы не создадите и не передадите структуру данных , которая будет содержать ссылку на функцию и аргументы, с которыми она должна работать.

В данном случае - генерики не являются решением. Вам следует рассмотреть другой шаблон, которому нужно следовать, например шаблон команды или шаблон стратегии, где вы передаете свои CheckConstruction экземпляры объектов-контролеров, каждый из которых создается с параметрами, с которыми он должен работать, и либо реализует, либо обеспечивается функцией проверки. .

...