several statements in lambda - c#

I have the following statement
var evarage = productionreportentry
.Sum(productionReportEntry => productionReportEntry.Cycletime);
I would like to add some logging inside the Sum lambda. Is this possible?

Yep, do something like:
var evarage = productionreportentry.Sum(productionReportEntry =>
{
Trace.Writeline(productionReportEntry.Cycletime);
return productionReportEntry.Cycletime;
});
Basically you add the curly brackets, and you need to explicitly return the value that the lambda is operating on, in this case the Cycletime which is used as part of the sum.

I am not sure what you really want but you can have multiple statements like this
var evarage = productionreportentry.Sum(productionReportEntry =>
{
CreateLog();
return productionReportEntry.Cycletime;
});

Related

Select multiple types in LINQ Select

Can this be turned into a select statement?
foreach (var gf in CreateGenericFieldsOnInspection(model))
{
simpleInspection.GenericFields.Add(gf.GenericFieldDefinition.Name,
new LC360Carrier.Domain.Models.Import.GenericField
{
GenericFieldType = GenericFieldValueType.Text,
Value = gf.Value
});
}
It looks like GenericFields is a Dictionary<string, GenericFieldOrSomething>. You could contort this into something really weird for the sake of using LINQ. But the purpose of LINQ is to query one or more IEnumerables to either get a result or transform them into something else.
It's just like SQL. You query it to either get a set of records or some value like the sum of some numbers.
In your case you've already got a result set - whatever CreateGenericFieldsOnInspection(model) returns. It makes sense to do what you're already doing - foreach through the results and perform some action on each one of them.
LINQ would be handy if you needed to query that set. For example,
var filteredProperties = CreateGenericFieldsOnInspection(model)
.Where(property => property.Name.StartsWith("X"));
But even then, once you had that collection, it would still make sense to use a foreach loop.
You'll see this sometimes - I did it when I first learned LINQ:
CreateGenericFieldsOnInspection(model).ToList()
.ForEach(property => DoSomethingWith(property));
We convert something to a List because then we can use .ForEach. But there's no benefit to it. It's just foreach with different syntax and an extra step.
I have an extension method that permits add. I was just having trouble w the syntax. Bagus Tesa, above was also helpful. Thanks.
simpleInspection.GenericFields = simpleInspection.GenericFields.Union(CreateGenericFieldsOnInspection(model).Select(x => new KeyValuePair<string, object>(x.GenericFieldDefinition.Name, new LC360Carrier.Domain.Models.Import.GenericField
{
GenericFieldType = GenericFieldValueType.Text,
Value = x.Value
}))).ToDictionary(x => x.Key, x => x.Value);

Select inside linq select

I have the following code (this is just relevant part):
linqQuery.Select(invoice =>
new InvoiceDetailed
{
UnpaidAmount = e.SumAmount +
e.OverdueNotices.OrderByDescending(on => on.SendDate).Select(on => on.Fee).DefaultIfEmpty(0).Sum() +
e.CreditNotes.Select(c => c.CreditNoteAmount).DefaultIfEmpty(0).Sum() -
e.Payments.Select(p => p.Amount).DefaultIfEmpty(0).Sum()
}
And this calculation for UnpaidAmount I repeat in severl other queries also. My question is if there is a way to somehow wrap that expression in function like:
Expression<Func<crmInvoice_Invoice, double>> unpaidExpression = // that unpaid amount caluculation expression
And then call like this:
linqQuery.Select(invoice =>
new InvoiceDetailed
{
UnpaidAmount = unpaidExpression(invoice)
}
Then I could reuse it in more queries. Is it possible to do something similar in LINQ? And if it is not is there any alternative solution u could suggest me to avoid repeating that part of code?
No, it's impossible.
Select method gets Expression as an argument. LINQ to SQL parses Expression to SQl code. So, to solve your task you need to convert you expression to return InvoiceDetailed:
Expression<Func<crmInvoice_Invoice, InvoiceDetailed>> InvoiceDetailedExpression = ...

Retrieve the two first elements that match a condition

I'm sure that this can be easily done with Linq but I can't figure it out.
var ls1 = plotter.Model.Series.FirstOrDefault(x => x.IsSelected);
var ls2 = plotter.Model.Series.FirstOrDefault((x => x.IsSelected)&&(ls2!=ls1));
What I'm pretending to do is to obtain the two first objects that have their property IsSelected set to true.
I can't use the syntax written above because the compiler can't use "local variable ls2 before it is declared".
Use Where to filter only the selected results then use Take to select the first two e.g.
plotter.Model.Series.Where(x => x.IsSelected).Take(2);
Try this:
var ls1and2 = plotter.Model.Series.Where(x => x.IsSelected).Take(2);
var ls1 = plotter.Model.Series.Where(x => x.IsSelected).Take(2);
You should use the Take method and do this
var ls1 = plotter.Model.Series.Where(x => x.IsSelected).Take(2);

Creating a Dynamic Where Clause as a Linq Expression

I am trying to dynamically append where conditions into a single expression-object, then pass that expression-object into a method that will use it. However, I keep getting "class name is not available at this point".
Thanks in advance!
UPDATE:
I finally was able to create a working example here.
The Code Look Like:
var view = new vw_QuickFindResult();
// This wont compile
Expression<Func<vw_QuickFindResult, bool>> where = Expression<Func<vw_QuickFindResult, bool>>(view, true);
// Build LIKE Statement
var searches = new List<String>(searchText.Split(' '));
searches.ForEach(productName =>
{
productName.Replace('"', '%');
productName.Replace('*', '%');
where = x => SqlMethods.Like(view.DocumentName, productName);
});
return DocumentCollectionService.ListQuickFind(where);
This is one problem:
where = x => SqlMethods.Like(view.DocumentName, productName);
You're ignoring the x here, instead using view which you've just initialized. I suspect you want:
where = x => SqlMethods.Like(x.DocumentName, productName);
However that will replace the existing where expression each time. I think you should be using PredicateBuilder by Joe Albhari. I'd avoid using ForEach too, personally:
var where = PredicateBuilder.False<vw_QuickFindResult>();
// Build LIKE Statement
foreach (string productName in searchText.Split(' '))
{
string like = productName.Replace('"', '%');
.Replace('*', '%');
where = where.Or(x => SqlMethods.Like(view.DocumentName, like));
}
return DocumentCollectionService.ListQuickFind(where);
(I'm guessing at the functionality you want; you may want PredicateBuilder.True and the And extension method instead.)

How to insert a lambda into a Linq declarative query expression

Let's say you have the following code:
string encoded="9,8,5,4,9";
// Parse the encoded string into a collection of numbers
var nums=from string s in encoded.Split(',')
select int.Parse(s);
That's easy, but what if I want to apply a lambda expression to s in the select, but still keep this as a declarative query expression, in other words:
string encoded="9,8,5,4,9";
// Parse the encoded string into a collection of numbers
var nums=from string s in encoded.Split(',')
select (s => {/* do something more complex with s and return an int */});
This of course does not compile. But, how can I get a lambda in there without switching this to fluent syntax.
Update: Thanks to guidance from StriplingWarrior, I have a convoluted but compilable solution:
var result=from string s in test.Split(',')
select ((Func<int>)
(() => {string u="1"+s+"2"; return int.Parse(u);}))();
The key is in the cast to a Func<string,int> followed by evaluation of the lambda for each iteration of the select with (s). Can anyone come up with anything simpler (i.e., without the cast to Func followed by its evaluation or perhaps something less verbose that achieves the same end result while maintaining the query expression syntax)?
Note: The lambda content above is trivial and exemplary in nature. Please don't change it.
Update 2: Yes, it's me, crazy Mike, back with an alternate (prettier?) solution to this:
public static class Lambda
{
public static U Wrap<U>(Func<U> f)
{
return f();
}
}
...
// Then in some function, in some class, in a galaxy far far away:
// Look what we can do with no casts
var res=from string s in test.Split(',')
select Lambda.Wrap(() => {string u="1"+s+"2"; return int.Parse(u);});
I think this solves the problem without the ugly cast and parenarrhea. Is something like the Lambda.Wrap generic method already present somewhere in the .NET 4.0 Framework, so that I do not have to reinvent the wheel? Not to overburden this discussion, I have moved this point into its own question: Does this "Wrap" generic method exist in .NET 4.0.
Assuming you're using LINQ to Objects, you could just use a helper method:
select DoSomethingComplex(s)
If you don't like methods, you could use a Func:
Func<string, string> f = s => { Console.WriteLine(s); return s; };
var q = from string s in new[]{"1","2"}
select f(s);
Or if you're completely hell-bent on putting it inline, you could do something like this:
from string s in new[]{"1","2"}
select ((Func<string>)(() => { Console.WriteLine(s); return s; }))()
You could simply do:
var nums = from string s in encoded.Split(',')
select (s => { DoSomething(); return aValueBasedOnS; });
The return tells the compiler the type of the resulting collection.
How about this:
var nums= (from string s in encoded.Split(',') select s).Select( W => ...);
Can anyone come up with anything
simpler?
Yes. First, you could rewrite it like this
var result = from s in encoded.Split(',')
select ((Func<int>)(() => int.Parse("1" + s + "2")))();
However, that's not really readable, particularly for a query expression. For this particular query and projection, the let keyword could be used.
var result = from s in encoded.Split(',')
let t = "1" + s + "2"
select int.Parse(t);
IEnumerable integers = encoded.Split(',').Select(s => int.Parse(s));
Edit:
IEnumerable<int> integers = from s in encoded.Split(',') select int.Parse(string.Format("1{0}2",s));

Categories