The ToDictionary() method call in this LINQ statement needs arguments. As it currently stands, the ToDictionary portion is a red squiggly, for lack of a better technical term. Error: No overload takes 0 arguments. Yeah, I know that.
I cannot add lambdas to the ToDictionary method call because Intellisense is overriding my lambda with its suggestion. In other words, if I type in "x ", it replaces it with XmlReader. Argh.
I've tried it with and without AsEnumerable. I borrowed most of this code from a StackOverflow post, but I added the dictionary portion.
Am I missing parentheses somewhere or something? Halllllp!
var props = (from p in _type.GetProperties()
let attr = p.GetCustomAttribute<ExcelExportAttribute>()
where attr != null && attr.ReportId.ToString() == reportID
select new {Prop = p, Att = attr })
.AsEnumerable()
.ToDictionary<PropertyInfo, ExcelExportAttribute>();
Error in VS
Severity Code Description Project File Line Suppression State Error CS1929 'IEnumerable<>' does not contain a definition for 'ToDictionary' and the best extension method overload 'Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer)' requires a receiver of type 'IEnumerable' WFG.UtilityLib.Excel C:\Users\kbessel\source\repos\WFG.UtilityLib.Excel\WFG.UtilityLib.Excel\ExcelExport.cs 142 Active
You need to completely leave out the generic types, like this:
.ToDictionary(x => x.Prop, x => x.Att);
The reason is that the extension method would need not two but THREE generic types: one for the "this" parameter, and two more for the "regular" parameters - or none, because the compiler can derive the types from the parameters.
You can specify all 3 types explicitly, but that would hardly serve any purpose because they can be derived automatically.
I cannot add lambdas to the ToDictionary method call because Intellisense is overriding my lambda with its suggestion. In other words, if I type in "x ", it replaces it with XmlReader.
This is a straightforward problem to overcome: type x, then press Esc to close down Intellisense drop-down. Continue typing the expression as needed:
var props = _type.GetProperties()
.SelectMany(p => new {Prop = p, Attr = p.GetCustomAttribute<ExcelExportAttribute>()})
.Where(p => p?.ReportId?.ToString() == reportId)
.ToDictionary(p => p.Prop, p => p.Attr);
Related
I am trying to call a EntityFramework method using reflection.
The signature of the method is
DbCollectionEntry<TEntity, TElement> Collection<TElement>
(Expression <Func<TEntity, ICollection <TElement>>> navigationProperty) where TElement : class
where TEntity is a type parameter of the class. How can construct a type which which will equal Expression <Func<TEntity, ICollection <TElement>>> so I can find the right overload of the method? I tried typeof(Expression<>).MakeGenericType(new[] { typeof(Func<,>) }); which displays the same in the debugger but doesn't match by equality. Once I have the method how do I call it? I managed to find the method by excluding the one with a string parameter but I still want find out how to match the method properly. I tried invoking the method using method.MakeGenericMethod(typeof(MyType)).Invoke(context.Entry(t), new[] { lambda }); but I get the exception "Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true." Here's what I have so far
var collectionMethod = typeof(DbEntityEntry<>)
.GetMethods()
.Where(m => m.Name == "Collection")
.Select(m => new { Method = m, Params = m.GetParameters(), Args = m.GetGenericArguments() })
.Where(x => x.Args.Length == 1 && x.Params[0].ParameterType != typeof(string))
.Select(x => x.Method)
.First();
var lambda = Expression.Lambda<Func<Trade, ICollection<TradeLeg>>>(prop, param);
// this fails
var o = collectionMethod.MakeGenericMethod(typeof(TradeLeg))
.Invoke(context.Entry(t), new[] { lambda });
var collectionMethod = typeof(DbEntityEntry<>)
This line condemns you to a failure, because the method will be looked for on the generic definition, not on the constructed type you use. The method must be identified on the concrete type, not on the definition, in order to call it. Based on your code, I assume the correct expression is typeof(DbEntityEntry<Trade>).
I've been following this tutorial today to learn a bit about the Web API and noticed something - in the tutorial code, there was this line:
var product = products.FirstOrDefault((p) => p.Id == id);
As you can see the parameter "p" is provided in parentheses. Since it's not mandatory having it this way, I'm curious if there's any benefit to doing it that way or if it's just a preference of the developer?
In this case, it's purely developer preference.
Parenthesises are needed when you have more than one parameter. For example:
var singleString = someStrings.Aggregate((current, next) => current + Environment.NewLine + next);
The C# specification explicitly states that (p) => ... can be written as p => ...:
7.15 Anonymous function expressions
...
In an anonymous function with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list. In other words, an anonymous function of the form
( param ) => expr
can be abbreviated to
param => expr
So there is no technical difference whatsoever, only personal preference.
How does one use Type.GetMethod() to get a method with lambda parameters? I'm trying to get the Queryable.Any method for a parameter of something like Func, using this:
typeof(Queryable).GetMethod("Any", new Type[]{typeof(Func<ObjType, bool>)})
but it keeps returning null.
There are four things wrong:
There's no such thing as a "lambda parameter". Lambda expressions are often used to provide arguments to methods, but they're converted into delegates or expression trees
You've missed off the first parameter of Queryable.Any - the IQueryable<T>
You're using Func<ObjType, bool> which is a delegate type, instead of Expression<Func<ObjType, bool>> which is an expression tree type
You can't get at generic methods in quite that way, unfortunately.
You want:
var generic = typeof(Queryable).GetMethods()
.Where(m => m.Name == "Any")
.Where(m => m.GetParameters().Length == 2)
.Single();
var constructed = generic.MakeGenericMethod(typeof(ObjType));
That should get you the relevant Any method. It's not clear what you're then going to do with it.
In EF, when you want to include a navigation property in the result of a query, you use Include(). Since some queries require calling this more than once, I tried to create a generic wrapper around this concept:
public IQueryable<T> FindAll<P>(params Expression<Func<T, P>>[] predicates) where P : class {
var entities = AllEntities();
foreach (var p in predicates) entities = entities.Include(p);
return entities;
}
And call it as such:
var customers = FindAll(q => q.Orders, q => q.Invoices, q => q.Contacts);
Questions:
The function compiles, but when I call it: "The type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly." What am I doing wrong?
If I get it to work, can I call Include() the first time: var customers = FindAll(q => q.Orders, q => q.Invoices); and then again later in a separate step: customers = customers.Include(p => p.Invoices); or will that result in poor performance such that I should do the includes in one go?
EDIT:
JonSkeet's answer is correct, of course, and yet there is this solution which seems to do what I want. Not sure why it works however. Is it because of the Aggregate() function?
Fundamentally, I think you've got a problem - assuming that q.Orders, q.Invoices and q.Contacts return different types, you can't express what you want to happen. You probably want something like:
entities.Include<Parent, Order>(p => p.Order);
entities.Include<Parent, Invoice>(p => p.Invoices);
entities.Include<Parent, Contact>(p => p.Contacts);
... so you want a different value for P for each predicate. But you're calling a single method, providing a single type argument for P.
It's not clear that this is really giving you much benefit anyway... couldn't you just write:
var customers = AllEntities().Include(q => q.Orders)
.Include(q => q.Invoices)
.Include(q => q.Contacts);
I'd say that's clearer and it gets round the "multiple type parameters" problem.
Is it mandatory that lambda expression need to use when LINQ will be used, or are lambda expressions optional?
In lambda expressions, the sign => is always used. What does it mean?
customers.Where(c => c.City == "London");
Here c => is used but why?
What kind of meaning of using c =>. Please discuss in detail because I don't know lambda.
No, you don't have to use a lambda expression. For example, your Where example could be written as:
private static bool IsLondon(Customer customer)
{
return customer.City == "London";
}
...
var londoners = customers.Where(IsLondon);
That's assuming LINQ to Objects, of course. For LINQ to SQL etc, you'd need to build an expression tree.
As to why "=>" is always used in a lambda expression, that's simply because that's the way the operator is written - it's like asking why "+" is used for addition.
A lambda expression of "c => ..." is effectively giving the lambda expression a parameter called c... in this case generic type inference provides the type of c. The body provides either an action to perform or some calculation to return a value based on c.
A full-blown description of lambda expressions is beyond the scope of this answer. As a blatant plug for my book, however, they're covered in detail in chapter 9 of C# in Depth.
The lambda expression
c => c.City == "London"
is shorthand for something like
bool IsCustomerInLondon(Customer c)
{
return (c.City == "London");
}
It's just a very concise way of writing a simple function that returns a value. It's called an "anonymous function" because it's never assigned a name or a formal definition (the parameter types and the return type are inferred from the context).
(Actually, it's not just shorthand; lambda expressions are related to some other constructs called closures, which are very cool and powerful tools.)
Think about lambdas as anonymous of functions.
I'll try to explain it with following code.
public bool IsLondon(Customer customer)
{
return customer.City == "London";
}
Now we strip down function name and get rid of braces:
public bool Customer customer
return customer.City == "London";
We don't need return type, because compiler is able to deduce type from expression:
customer.City == "London";
In the same manner compiler knows about input type, so we don't need to specify it.
So basically, what we left with is
customer
return customer.City == "London";
And lambda syntax in c# is basically:
(parameter list) => "expression"
You can also write "multi-line" expressions, but then you have to surround your code with curly braces. Also you will need to use "return" statement, like you usually do.
Jon already answered,
but I'd like to add this.
In the example you have given, imagine Linq looping over all customers,
and c is simply a reference to each item in the enumerable:
var result = new List<Customer>();
foreach(var c in customers)
{
if (c.City == "London")
result.Add(c);
}
return result;
It's a variable like any other, it does not have to be a single named one,
but it's just a convention of some sort.
you do not need to use lambda expressions on Lİnq to sql or Entities; here is an alternative way of your code;
you code :
customers.Where(c => c.City == "London");
the other way;
var query = from cs in customers
where cs.City == "London"
select cs;
this is the another way. it is up to you.
Lambda and linq are quite separate. You can use one without using the other (there are parts of linq that depend on lambda expressions, but we want to keep it simple :-) )
A lambda expression is an anonymous
function that can contain expressions
and statements, and can be used to
create delegates or expression tree
types.
This was from MSDN. (http://msdn.microsoft.com/en-us/library/bb397687.aspx )
To make it short (it's much more complex) you can use a lambda expression to make a local function. what you put before the => (in your example the c) will be the parameter of the function. The return type is "discovered" by the C# compiler.
c => c.City == "London" is nearly equivalent to:
delegate (TheObjectTypeOfC c) {
return c.City == London
};
(the difference is that some lambda expression are delegates and also expressions, but please ignore this, you won't need it for some time)
If/when the compiler isn't able to infer the types of the parameters, you can force them: (MyObject p) => p.SomeProperty != null. Here you are telling the compiler that p is a parameter.
While here I showed you what are called "expression lambdas", you can even do "statement lambdas":
p => {
for (int i = 0; i < 10; i++) {
if (p.SomeProperty == 0) {
return true;
}
}
return false;
}
(I won't tell you what are the "behind the scenes" differences between expression lambdas and statement lambdas. If you want to know them, read the msdn page I pointed before)
No it is not necessary at all.
We have two ways to write LINQ queries.
One is query method and other is builder method. You only need to put lambda expression in case of builder method.
For example, if we want to find all those students from some Students object that have more marks than 70.
but we can do this thing in LINQ with following syntax
var data = from p in stdList
where p.marks > 70
select p;
or
var data = stdList.Where(p=>p.marks > 70);
later approach is builder method, in Where function, we are passing lambda expressions.
Lambda expressions are just short cuts of doing things you can always use LINQ queries but if you want to avoid whole query syntax for just applying a simple condition you can just use LINQ builder methods (which asks for lambda expressions) in lambda expressions, you always define some alias and then perform your operation.
As far as => operator is concerned, It works just like assignment operator.
For example:
(p) => p.Gender == “F”
It means “All persons p, such that person’s Gender is F”
In some literature this is called “predicate”. Another literature terminology is “Projection”
(p) => p.Gender ? “F” : “Female”
“Each person p becomes string “Female” if Gender is “F””
This is projection, it uses ternary operator.
Although i explained with very basic examples but i hope this would help you . . . :)