Reputation: 635
I have the following methods:
private List<T> GetEntities<T>(T entity) {
// ...
}
and
public virtual List<T> Find<T>(Predicate<T> match) {
// ...
}
How can I get the values of the lambda expression in the Predicate<T>
?
I would like to do something like:
var result = Find<MyObject>(o => o.Name == "Something")
and in the Find
method I would:
public virtual List<T> Find<T>(Predicate<T> match) {
// ...
string name = myObj.Name // equals to "Something"
return GetEntities<T>(myObj) //Note that here is my object with the parameters passed via lambda
// ...
}
How can I do this?
Edit: There is already a method that receives MyObject, I just want a method that I can use lambda expressions, without instantiating an object just to filter an entity. No idea if I use Func or Predicate
Edit 2: As requested, here is a concrete example of what i would achieve:
Currently, when I want to retrieve an object with specific filters, I use:
Person p = new Person() { Name = "John" };
var result = GetEntities<Person>(p);
What I like to do:
var result = Find<Person>(p => p.Name = "John");
however, internally would like to continue using the previous method, I would just turn up the expression into a object and then use GetEntities<Person>(p)
Conclusion: I made a really lot of confusion with predicates and Func's. I thought I could treat them as objects, but are expressions and my question completely ran off the concept of these elements.
Upvotes: 0
Views: 7154
Reputation: 4703
From the signature and usage, following code is what I inferred for you. It compiles, however, it's incorrect for use.
Classes
public partial class MyObject {
public String Name;
}
public partial class MyGeneric<U> where U: MyObject {
private List<T> GetEntities<T>(T entity) where T: U {
throw new NotImplementedException(); // not implemented yet
}
public virtual List<T> Find<T>(Predicate<T> match) where T: U {
foreach(var myObj in m_List)
if(match(myObj as T)) {
// ...
var name=myObj.Name;
// ...
return this.GetEntities(myObj as T);
}
return new List<T>();
}
List<U> m_List;
}
Test
var myGeneric=new MyGeneric<MyObject>();
var result=myGeneric.Find<MyObject>(o => o.Name=="Something");
Here're something I'd like to tell:
You might misunderstood of generic.
As you see the class MyGeneric
and those two method, all have constraints. From the usage of your code, almost cannot go without these constraints, but this is just unnecessarily complicated.
You might misunderstood of Predicate<T>
and also lambda expressions
The definition of Predicate<T>
is
public delegate bool Predicate<T>(T obj);
That is, it's a delegate. obj
is the argument pass to the delegate. Therefore you cannot get obj
with a different context. However, you can do something like
MyObject x;
var myGeneric=new MyGeneric<MyObject>();
var result=myGeneric.Find<MyObject>(o => (x=o).Name=="Something");
Here x
references to o
, but with your Find
method, it's not possibly to do. So the object pass to the Predicate<T>
, must already be somewhere you can access it, otherwise you can never.
I post with the code that demonstrates what the compilable syntax of statement that you can do, and even possibly works. But I STRONGLY suggest that DON'T do something like this.
Upvotes: 3
Reputation: 26687
In your example, this would be proper:
public virtual List<T> Find(T myObj)
{
return GetEntities(myObj);
}
You need to pass predicate (Func<T, bool>
) only if you want to filter item from IEnumerable, and you don't have any IEnumerable in your question. If you would have IEnumerable then:
private IEnumerable<T> _list;
public virtual List<T> Find(Func<T, bool> predicate)
{
T myObj = _list.FirstOrDefault(predicate);
return GetEntities(myObj);
}
To expand a bit, yours o => o.Name == "Something"
is equivalent to:
private bool Filter(MyObject enumeratedObject)
{
return enumeratedObject.Name == "Something";
}
It doesn't contain any value until enumeration happens and starts calling Filter(...) for each element of the list.
Upvotes: 0
Reputation: 11287
Try this
public virtual List<T> Find<T>(Func<T,bool> match)
{
return lst.Where(match).ToList();
}
Upvotes: 0
Reputation: 590
If I understand your question right, your second method should be something like this:
public virtual List<T> Find<T>(Expression<Predicate<T>> match)
{
return _myCollection.Where(match).ToList();
}
You can then pass a lambda expression into the method and get a list of matches back.
Upvotes: 0