I have the following method that I can't figure out correct syntax to call:
public T GetAndProcessDependants<C>(Func<object> aquire,
Action<IEnumerable<C>, Func<C, object>> dependencyAction) {}
I'm trying to call it like this:
var obj = MyClass.GetAndProcessDependants<int>(() => DateTime.Now,
(() => someList, (id) => { return DoSomething(x); }) }
Edited:
thx everyone, you guys helped turned on a light bulb in my head. here is what i did:
var obj = MyClass.GetAndProcessDependants<int>(
() => DateTime.Now,
(list, f) =>
{
list = someList;
f = id => { return DoSomething(id); };
});
not sure why i even an issue with this. it's one of those days i guess..
thx
Your lambda syntax is totally wrong.
You need to create a single lambda expression with two parameters:
(list, id) => DoSomething(...)
Right now the function is only accepting a single argument, when it asks for two!
You need to accept a list argument, such as (list, id) => {}
Just looking at the description above, it looks like the call should be:
var obj = MyClass.GetAndProcessDependants<int>(() => DateTime.Now,
(seq, fun) => { /* do something with seq and fun */ });
The key is since you are passing an Action that takes a Func, the caller is (most likely) going to be the one passing that Func into your Action. So you just specify how that Func is applied to the sequence passed in (if I'm reading the prototype correctly).
var obj = MyClass.GetAndProcessDependants<int>(
() => DateTime.Now,
(someList, id) => DoSomething(x)
);
Related
Is there a way to parameterize the Contains portion of Linq when linked to an array.
I have the following code.
var query = Data.Where(s => an_array.Contains(s.Name)).Distinct().ToList();
How can I parameterize s.Name so I can create a method that uses a func or something else?
I am used to using (Func<Model, T> param ) and using it in linq where the input looks like (s=>s.Name), but I am stuck because the Contains portion is just looking for (s.Name)
I have tried using (Func<Model, string> param ) but that doesn't seem right.
Thanks!
Update 1:
If I have a method like below, where s.Name changes depending on user input.
How can I pass that to the method.
public void GetFilteredItems()
{
var queryresult = Data.Where(s => an_array.Contains(s.Name)).Distinct().ToList();
}
Ideally would like something like this so it will work with whatever is passed.
public void GetFilteredItems(Func<?,?> param)
{
var queryresult = Data.Where(s => an_array.Contains(param)).Distinct().ToList();
}
Is this what you want?
Func<Model, string> p = s => s.Name;
var query = Data.Where(s => an_array.Contains(p(s))).Distinct().ToList();
I think what you want is Any, rather than Contains. One of the overloads takes a predicate that you can use to test for a specific condition:
public void GetFilteredItems<T>(Func<T, bool> predicate)
{
var queryresult = Data.Where(s => an_array.Any(predicate)).Distinct().ToList();
}
I have a little problem with how to call my function.
Before, I only needed one parameters and i wrote the function like that (i absolutely need to call it like that) :
public void SetDialogs(UnityAction pFunctionClic){blablabla};
SetDialogs(() => MyClicFunction());
Now, i need to have multiple function in the parameters. So, i set my SetDialogs function like this :
public void SetDialogs(UnityAction[] pFunctionClic){blablabla};
Now, the problem is that i don't know what to write when i call my function.
Obviously
SetDialogs(() => [MyClicFunction()]);
doesn't work.
Can you help me please ?
I haven't used Unity before, but judging by what you're doing, you can pass an array of UnityAction as such:
SetDialogs(new UnityAction[] {
() => MyClickFunction(),
() => SomeOtherStuff(),
});
You can use a params array parameter. A params parameter must always be the last (or the only one) in the parameter list
public void SetDialogs(params UnityAction[] pFunctionClic){ ... };
Now you can pass it with as many UnityAction parameters as you need.
SetDialogs(() => MyClicFunction());
SetDialogs(() => MyClicFunction1(), () => MyClicFunction2());
SetDialogs(() => MyClicFunction1(), () => MyClicFunction2(), () => MyClicFunction3());
Inside the method you always see an array. When calling the method you don't need to pass it an array (C# converts the parameters to an array automatically); however, you can:
var unityActions = new UnityAction[] {
() => MyClicFunction1(),
() => MyClicFunction2(),
() => MyClicFunction3()
};
SetDialogs(unityActions);
I have a function which uses the "Any" method on a list.
List<String> list = Factory.ReturnList(); //Returns a list of all countries in Europe
I need to verify that the list contains partial strings like "(DE)" and "(FR)", ...
Assert.Equal(list.Any(item=> item.Contains("(DE)")), true);
Assert.Equal(list.Any(item=> item.Contains("(FR)")), true);
Assert.Equal(list.Any(item=> item.Contains("(BE)")), true);
Assert.Equal(list.Any(item=> item.Contains("(NL)")), true);
Now I would like to write it as a function. I have seen other people use code like this:
Func<IWebElement, bool> condition = item => item.Text == "something";
Assert.Equal(list.Any(condition), true);
I already tried the following, but that didn't work:
Func<List<String>, bool> condition = list.Any(x => x.Contains(input));
Due to:
Cannot implicitly convert type 'bool' to 'System.Func<System.Collections.Generic.List<string>, bool>'
How can I do that in my example?
'input' needs to be a parameter/variable so the Func can be invoked with different parameters
You are currently invoking the method and trying to assign it to your Func which of course doesn't work since you've already invoked it, returning bool.
Instead, encapsulate the two input arguments and update the Func signature to match your intent.
Func<List<String>, string, bool> condition =
(list, input) => list.Any(x => x.Contains(input));
You can then invoke your Func like so:
Assert.Equal(condition(new List<string>(), ""), true);
This gives you the highest degree of flexibility and reusability since the condition is constant, but the parameters can change.
If you just want a lambda expression, use:
Func<List<String>, bool> condition = (list,input) => list.Any(x => x.Contains(input));
How about putting those strings into an array?
string[] countries = { "DE", "FR", "BE", "NL" };
result = from item in list
where countries.Any(val => item.Contains(val))
select item;
I have next chunk of code
var query = wordCollection.Select((word) => { return word.ToUpper(); })
.Where((word) =>
{
return String.IsNullOrEmpty(word);
})
.ToList();
Suppose I want to refactor this code and extract the lambda expression from Where clause. In Visual Studio I just select this lambda and do Refactor -> Extract Method. By doing so I have my LINQ modified to
var query = wordCollection.Select((word) => { return word.ToUpper(); })
.Where(NewMethod1())
.ToList();
and a NewMethod1() is declared as
private static Func<string, bool> NewMethod1()
{
return (word) =>
{
return String.IsNullOrEmpty(word);
};
}
The question is why this new method does NOT have any input parameters, as delegate Func states that NewMethod1() should have a string input parameter?
To get the expected result, mark just this part String.IsNullOrEmpty(word) and Extract the method:
private bool NewMethod(string word)
{
return String.IsNullOrEmpty(word);
}
What you originally got is because the extract created a method that returns a delegate. Not a method that matches the delegate. It is a method that returns another method. The latter accepts a string parameter word and returns a bool result.
Sure doing the above changes your code to:
.Where((word) => NewMethod(word))
But you can safely change that to:
.Where(NewMethod)
Side Note:
No need to use the return keyword in your Linq Queries or any one-line lambda, you can refactor you query to be like this:
var query = wordCollection.Select(word => word.ToUpper())
.Where(word => string.IsNullOrEmpty(word))
.ToList();
You are selecting the whole lambda, so it is trying to extract the whole lambda statement as a delegate that takes in a word and returns a boolean - Func < string, bool>.
When refactoring you should have only selected the "return String.IsNullOrEmpty(word);" part.
Additionally, you are using the lambas in an unnecessarily complex way.
You could refactor your LINQ statement to this:
var query = wordCollection.Select(word => word.ToUpper())
.Where(word => String.IsNullOrEmpty(word))
.ToList();
Or even to this:
var query = wordCollection.Select(word => word.ToUpper())
.Where(String.IsNullOrEmpty)
.ToList();
IQueryable<Organization> query = context.Organizations;
Func<Reservation, bool> predicate = r => !r.IsDeleted;
query.Select(o => new {
Reservations = o.Reservations.Where(predicate)
}).ToList();
this query throws "Internal .NET Framework Data Provider error 1025" exception but the query below does not.
query.Select(o => new {
Reservations = o.Reservations.Where( r => !r.IsDeleted)
}).ToList();
I need to use the first one because I need to check a few if statements for constructing the right predicate. I know that I can not use if statements in this circumstance that is why I pass a delegate as parameter.
How can I make the first query work?
While the other answers are true, note that when trying to use it after a select statement one has to call AsQueryable() explicitly, otherwise the compiler will assume that we are trying to use IEnumerable methods, which expect a Func and not Expression<Func>.
This was probably the issue of the original poster, as otherwise the compiler will complain most of the time that it is looking for Expression<Func> and not Func.
Demo:
The following will fail:
MyContext.MySet.Where(m =>
m.SubCollection.Select(s => s.SubItem).Any(expr))
.Load()
While the following will work:
MyContext.MySet.Where(m =>
m.SubCollection.Select(s => s.SubItem).AsQueryable().Any(expr))
.Load()
After creating the bounty (rats!), I found this answer, which solved my problem. (My problem involved a .Any() call, which is a little more complicated than this question...)
In short, here's your answer:
IQueryable<Organization> query = context.Organizations;
Expression<Func<Reservation, bool>> expr = r => !r.IsDeleted;
query.Select(o => new { Reservations = o.Reservations.Where(expr) })
.ToList();
Read the referenced answer for an explanation of why you need the local variable expr, and you can't directly reference another method of return type Expression<Func<Reservation, bool>>.
Thanks for pinging me. I guess I was on the right track after all.
Anyway, to reiterate, LINQ to Entities (thanks to Jon Skeet for correcting me when I got mixed up in my own thought process in the comments) operates on Expression Trees; it allows for a projection to translate the lambda expression to SQL by the QueryProvider.
Regular Func<> works well for LINQ to Objects.
So in this case, when you're using the Entity Framework, any predicate passed to the EF's IQueryable has to be the Expression<Func<>>.
I just experienced this issue in a different scenario.
I have a static class full of Expression predicates which I can then combine or pass to an EF query. One of them was:
public static Expression<Func<ClientEvent, bool>> ClientHasAttendeeStatus(
IEnumerable<EventEnums.AttendeeStatus> statuses)
{
return ce => ce.Event.AttendeeStatuses
.Where(a => a.ClientId == ce.Client.Id)
.Select(a => a.Status.Value)
.Any(statuses.Contains);
}
This was throwing the 1025 error due to the Contains method group call. The entity framework expected an Expression and found a method group, which resulted in the error. Converting the code to use a lambda (which can be implicitly cast to an Expression) fixed the error
public static Expression<Func<ClientEvent, bool>> ClientHasAttendeeStatus(
IEnumerable<EventEnums.AttendeeStatus> statuses)
{
return ce => ce.Event.AttendeeStatuses
.Where(a => a.ClientId == ce.Client.Id)
.Select(a => a.Status.Value)
.Any(x => statuses.Contains(x));
}
Aside: I then simplified the expression to ce => ce.Event.AttendeeStatuses.Any(a => a.ClientId == ce.Client.Id && statuses.Contains(a.Status.Value));
Had a similar problem. Library of ViewModels that look like this:
public class TagViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public static Expression<Func<SiteTag, TagViewModel>> Select = t => new TagViewModel
{
Id = t.Id,
Name = t.Name,
};
This works:
var tags = await db.Tags.Take(10).Select(TagViewModel.Select)
.ToArrayAsync();
But, this won't compile:
var post = await db.Posts.Take(10)
.Select(p => new {
Post = p,
Tags = p.Tags.Select(pt => pt.Tag).Select(TagViewModel.Select)
})
.ToArrayAsync();
Because the second .Select is a mess - the first one is actually called off of an ICollection, which is not IQueryable, so it consumes that first Expression as a plain Func, not Expression<Func.... That returns IEnumerable<..., as discussed on this page. So .AsQueryable() to the rescue:
var post = await db.Posts.Take(10)
.Select(p => new {
Post = p,
Tags = p.Tags.Select(pt => pt.Tag).AsQueryable()
.Select(TagViewModel.Select)
})
.ToArrayAsync();
But that creates a new, weirder problem: Either I get Internal Framework...Error 1025, or I get the post variable with a fully loaded .Post property, but the .Tags property has an EF proxy object that seems to be used for Lazy-Loading.
The solution is to control the return type of Tags, by ending use of the Anonymous class:
public class PostViewModel
{
public Post Post { get; set; }
public IEnumerable<TagViewModel> Tags { get; set; }
Now select into this and it all works:
var post = await db.Posts.Take(10)
.Select(p => new PostViewModel {
Post = p,
Tags = p.Tags.Select(pt => pt.Tag).AsQueryable()
.Select(TagViewModel.Select)
})
.ToArrayAsync();