Reputation: 3224
My first (and really horrible post) is below.
I try to do a complete example what I want to get. I hope this will be left explained a bit better.
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;
}
}
}
}
============== first post ===================== Hello,
I have a class with methods:
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);
}
}
Sorry if there is some error, I have written from scrach to avoid complex real case.
What I want is call my methods like this:
X.check1("Jhon");
or
X.check2(12);
or (this is the goal of my question):
X.CheckConditions(X.check1("Jhon"), X.chek2(12));
Thanks and sorry by my poor example...
Upvotes: 5
Views: 10092
Reputation: 3366
What you pass to your
X.CheckConditions
is not a reference to the functions, but the returned value of their invocation.
Now, if you pass function reference - it does not come with parameters, unless you construct and pass a data-structure that will contain the function reference and the arguments it should work on.
In this case - generics is not the solution. You should consider another pattern to follow, like command pattern or strategy pattern, where you pass to your CheckConstruction
instances of checker-objects, each is instantiated with the parameters it should work on, and either implements or is provided by the validation function.
Upvotes: 0
Reputation: 110201
It is unclear where your T comes from.
Does this meet your requirements?
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();
}
}
Then later:
List<T> result = X.CheckConditions(
z => z.FieldS == "Jhon",
z => z.FieldI == 12
);
Upvotes: 3
Reputation: 21752
you could rewrite you function to look like this:
// 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));
}
}
your call would then be X.CheckConditions(()=>X.check1("Jhon"), ()=>X.chek2(12));
and you need to provide an instance for x (since the methods are instance methods and not static methods)
In your example you pass T as an argument to the functor but T is a type argument som it can't be passed as an argument to the method. Did you mean to pass a value?
This begs for a clarification of why you would want to do this. Maybe if you provided details on what you are trying to accomplish (as opposed to how) then you could get a better solution to your problem.
Upvotes: 0
Reputation: 156025
There's no reason to make it generic, you know that you want to operate on the current instance of X
(so pass in this
, instead of the T
type parameter). You need to cleanup a few things to to get it to compile (return result
and make the type of result
and the Intersect
call compatible). You can define it like this:
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();
}
Ant then call it like this:
xInstance.CheckConditions(x => x.check1("JHon"), x => x.check1(12));
All that said, I'm not sure why you wouldn't just pass around the results of these functions, instead of passing the actual functions around:
public List<string> CheckConditions(params List<string>[] conditions)
{
IEnumerable<string> result = myList;
foreach (var condition in conditions)
{
result = result.Intersect(condition);
}
return result.ToList();
}
Then call it as in your example, rather than passing in lambda expressions.
Upvotes: 1
Reputation: 37516
You need to change the method signature of CheckConditions
, it's accepting a variable number of List<string>
, not functions.
public List<string> CheckConditions(params List<string>[] lists)
The return type of check1
is List<string>
, so that needs to be the type of the parameter that CheckConditions
accepts.
Upvotes: 2