Func<> or method in test code? - c#

I saw this loop in test code:
foreach ( StuffId Id in Result.GetIdList() )
{
if ( Id.Level == 3 )
{
Level3Id = Id.ToString();
}
if ( Id.Level == 5 )
{
Level5Id = Id.ToString();
}
}
Other tests imply that either there is only one Id for each level or when there are multiples for each level then the Id will be the same.
Being slightly obsessed with LINQ right now, I first refactored to this:
IEnumerable<StuffId> Ids = Result.GetIdList();
Level3Id = Ids.Where( x => x.Level == 3 ).First().Id.ToString();
Level5Id = Ids.Where( x => x.Level == 5 ).First().Id.ToString();
Then the code repetition bothered me so I refactored to this:
IEnumerable<StuffId> Ids = Result.GetIdList();
Func<int,string> IdFromLevel =
level => Ids.Where( x => x.Level == level ).First().Id.ToString();
Level3Id = IdFromLevel(3);
Level5Id = IdFromLevel(5);
A colleague wondered why I didn't use a method in place of the delegate. My reasoning is a method would be slightly more 'messy' because I'd have to additionally pass in the collection and that using a delegate is no big deal for a simple test (for which terse, readable and no branching are good qualities).
I had a look on SO, of course, and found this seemingly relevant question:
C#: Func<> instead of methods?
where the consensus seems to favour a method over a delegate. Does the same apply in my case?

It is a question of reuse. If you are using methods that might be reusable in other cases, you should define them seperately.
But if you have only short statements that additionally vary, you should stick with anonymous functions/lambda-expressions, these might result in a better runtime-behavior.
From SO:
There is no advantage in the code you posted. In your code, using the delegate just adds complexity as well as an extra runtime cost - so you're better off just calling the method directly.
However, delegates have many uses. "Passing around" to other methods is the primary usage, though storing a function and using it later is also very useful.
LINQ is built on top of this concept entirely. When you do:
var results = myCollection.Where(item => item == "Foo");
You're passing a delegate (defined as a lambda: item => item == "Foo") to the Where function in the LINQ libraries. This is what makes it work properly.

Not sure about pros and cons, but reading these articles might help you to take a better decision:
http://msdn.microsoft.com/en-in/library/bb549151.aspx
http://msdn.microsoft.com/en-us/library/orm-9780596516109-03-09.aspx
http://msdn.microsoft.com/en-in/library/98dc08ac.aspx

I would go with the first block:
foreach (StuffId Id in Result.GetIdList())
{
if (Id.Level == 3)
{
Level3Id = Id.ToString();
}
if (Id.Level == 5)
{
Level5Id = Id.ToString();
}
}
This does loop the collection only once. I see you don't worry about performance here, but for me its not a matter of performance or optimization. It's a matter of doing something logically correct way. Why do something twice if it could be in one step (provided readability is not hurt).
The added benefit is that you don't have the dilemma between Func<,> and method, and the related complexities. As far as number of characters or ease of typing goes, its almost the same, except you're writing it horizontally (in the second case) than vertically. You can even write the above in two lines inside the foreach block.
If you're bent on writing the two actions separately, I would make the choice based on whether the function has relevance outside the scope of current method in this case. It seems to me that its a trivial predicate which is relevant only for the two assignments. So I like:
var Ids = Result.GetIdList();
Func<int, string> IdFromLevel = level => Ids.Single(x => x.Level == level).Id.ToString();
Level3Id = IdFromLevel(3);
Level5Id = IdFromLevel(5);
Prefer Single here over First..

Related

Howto add a subset of a List to a property of an object in another List - best/fastest practice

I'm trying to find the fastest and most performant way to select a subset of items from a list based on a key property and assign this subset (list) to the property of an item in another list. The performance side of this is important since this part of code is going to be invoked very often each workday. I measured the performance in ticks to clearly see the relative difference.
I've got two lists (example setup);
List<CategorySetting> catList;
List<Customer> custList;
The CategorySetting entity has a property called SettingsId. The Customer entity has a SettingsId property as well, which is in fact a foreign key from Customers to CategorySetting.
The first piece of code i wrote was the most straight forward;
// normal for each: 13275 ticks
foreach (var catItem in catList)
{
catItem.Customers = custList.Where(c => c.SettingsId == catItem.SettingsId).ToList();
}
This would take about 13275 ticks.
I then thought maybe using parallelism this could be a lot faster? So I wrote this piece of code;
// parallel for each: 82541 ticks
Parallel.ForEach(catList, catItem =>
{
catItem.Customers = custList.Where(c => c.SettingsId == catItem.SettingsId).ToList();
});
This took way longer; 82541 ticks. That made no sense to me because of the parallel nature of this approach. It should use multiple threads to do this so in theory should be much faster. Then I started wondering what would happen if the multiple threads would try to access the customerlist at the same time. That might result in locks and queues hence taking more time because of the overhead? The same as for the writing to the main list.
I tried another approach. I made a ConcurrentBag for the catList (main list).
ConcurrentBag<CategorySettings> csBag = new ConcurrentBag<CategorySettings>(catList);
The custList I punt into a ConcurrentDictionary already grouped by the SettingsId.
var dict = custList.GroupBy(c => c.SettingsId).ToDictionary(x => x.Key, y => y.ToList());
ConcurrentDictionary<int?, List<Customer>> concDict = new ConcurrentDictionary<int?, List<Customer>>(dict);
The final try was then like this:
// paralell, bag, concurrent dictionary: 40255
Parallel.ForEach(caBag, ca =>
{
concDict.TryGetValue(ca.SettingsId, out var selCust);
ca.Customers = selCust;
});
This would take 40255 ticks. Can anyone explain why this is still taking longer? And more important is there no other way then 'just' a foreach loop? Feels like i'm missing something here.
Any ideas are greatly appreciated!
You could try using the ToLookup LINQ method:
var customersLookup = custList.ToLookup(item => item.SettingsId);
foreach (var catItem in catList)
{
catItem.Customers = customersLookup[catItem.SettingsId].ToList();
}
I assumed that the CategorySetting class has a writable property Customers of type IList<Customer>. In case the property is of type IEnumerable<Customer>, you could omit the ToList call.
I ended up using what I had;
foreach (var catItem in catList)
{
catItem.Customers = custList.Where(c => c.SettingsId == catItem.SettingsId).ToList();
}
#NetMage pointed out very well that this is probably useless optimalisation. I figured that the paralell foreach would be of major use here, but no matter what, the first loop was still the fastest. Both on my quadcore and on my xeon.

Iterating through two Lists and checking the item value of the first list to the item values of the second list with a lambda expression

So in the program I'm trying to run I receive two lists, one with objects that contain an id in string format (looks something like "bb_b1203322") and one list with the id's(which in this place is only named "b1203322" for reasons unknown) and a description of the actually id's meaning.
var forms = await _tRepository.GetAllFormsAsync(lastUpdate);
var formDefinitions = await _deRepository.GetAllFormDefintionsAsync();
foreach (var form in forms)
{
foreach (var def in formDefinitions)
{
if (form.SetupFormName.Contains(def.BLKID))
form.SetupFormName = def.DESCR;
}
}
return forms;
Now this piece of code does exactly what I want it to, but I'd rather have it as a lambda expression because ... reasons :)
Now I've tried several different things but with my current knowledge of lambda expressions I can't get it to work.
Try this code. Note that you can use it if formDefinitions with suitable DESCR always exists.
forms.ForEach(f => f.SetupFormName = formDefinitions.FirstOrDefault(fd =>
f.SetupFormName.Contains(fd.DESCR)).DESCR);
This code uses a bit of LINQ to find the definition:
foreach(var form in forms)
{
var def = formDefinitions.FirstOrDefault(x => form.SetupFormName.Contains(x.DESCR));
if(def != null)
form.SetupFormName = def.DESCR
}
As you can see, it's not really saving all that much code.
Please note:
As Jon correctly comments, the behavior of this code is a bit different from your original one. This code uses the first occurrence if there are multiple and your code uses the last occurrence.
If this is actually a use case for your code, replace FirstOrDefault with LastOrDefault.
Extending the code above, you can do something like this:
foreach(var tuple in forms.Select(x => new { Form = x,
Definition =
formDefinitions.FirstOrDefault(y =>
x.SetupFormName.Contains(y.DESCR)) })
.Where(x => x.Definition != null))
{
tuple.Form.SetupFormName = tuple.Definition.DESCR;
}
But as you can see, this gets messy real quick.

Using values from foreach in QueryOver statement

say I want to iterate over a list of IDs and use them to compare some properties in a QueryOver-statement as in:
foreach(int id in myIdList)
{
QueryOver<Tabe> query = QueryOver.Of<Table>()
.Where(t => t.SomeForeignKey == id);
}
Now my compiler advised me to create an extra variable for the iterator id, as it will otherwise be treated as a closure accessing a foreach-variable. So to be on the safe side I adjustet the code to:
foreach(int id in myIdList)
{
int id1 = id;
QueryOver<Tabe> query = QueryOver.Of<Table>()
.Where(t => t.SomeForeignKey == id1);
}
And the compiler stopped complaining.
For the first version the compiler said, that the behaviour of the statement differs depending on the compiler version, so I am wondering in which cases it would be save to use the first expression and why it produces correct / incorrect results. And why is it in the end better to use the second version?
Thank you for any insights!
I suggest you to read more about Closures, you can see the more details about usage in C# at "Delegates (C#, D)" section of the link

What's the syntax for this linq expression calling the in method

I have to query a repository where column a = {myvalue} and column b has any value in a collection.
Here's what I have:
Application[] applicationCollection = GetAllApplications();
var result = repo.GetAll(r => r.Email == myEmail && r.Application.In(applicationCollection));
I can't figure out how to write the "in" part...
Preferrably links to how to do this would be best, so I can learn it, as opposed to just getting the answer :). Thanks all.
(I'm sure this is a repeat question, but my Google/search skills are obviously poor.)
The SQL idea of item in collection is written in C# (including LINQ) as collection.Contains(item). In your example, this might be:
var result = repo.GetAll(r => r.Email == myEmail &&
applicationCollection.Contains(r.Application));
ApplicationCollection.Contains(r.Application)
Use .Contains(collection) instead of in. Here's a link since you wanted one.
If you want to write it the way you've shown, you can write this extension method:
public static bool In<T>(this T item, IEnumerable<T> set)
{
return set.Contains(item);
}
And then use it exactly like you did in your question:
Application[] applicationCollection = GetAllApplications();
var result = repo.GetAll(r =>
r.Email == myEmail &&
r.Application.In(applicationCollection));
This will work fine if you're only working with in-memory sets. If you're doing something like LINQ-to-SQL, however, this won't be compatible.
Note: I'm not trying to imply that this extension method might be a good idea to use - I'm just saying it's possible to write one like that.

LINQ? Refactoring foreach

Is there a better way to write this? I feel like I'm getting rusty with C# after doing a lot of JavaScript lately. Can this be improved?
foreach (var item in this.CartItems)
{
if (item.EffectivePrice != null)
{
this.CartItems[this.CartItems.IndexOf(item)].EffectivePrice =
CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
}
}
Well, you could write it in LINQ query syntax with a from and a where, but I'm not sure it is a big change; I'd be more interested in knowing if the lookup is unnecessary:
this.CartItems[this.CartItems.IndexOf(item)].EffectivePrice =
CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
to:
item.EffectivePrice = CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
Other than that, I'm not sure it is worth the bother of changing it; I'd probably leave it as:
foreach (var item in this.CartItems) {
if (item.EffectivePrice != null) {
item.EffectivePrice = CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
}
}
Straight up answer to your question (about how to implement your code in Linq):
this.CartItems.Where(item => item.EffectivePrice != null).ToList().ForEach
(
item =>
item.EffectivePrice = CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
);
There is no reason to have to explicitly specify the index of the item in the list (at least I haven't seen a reason). The .ToList() gives you a List<T> of object references for you to manage. You AsQueryable() to save a few CPU cycles.
It's a little strange, however, to overwrite a property with the results of the method call as subsequent method calls on that property may alter the value over and over again.
But, nonetheless, Linq's method is far more elegant. The drawback, that I can see, is the inability to edit-and-continue with any method that contains Linq.
I think you can do something like this:
foreach (var item in this.CartItems.Where(i => i.EffectivePrice != null))
{
item.EffectivePrice =
CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
}
In addition to Marc's point, LINQ is more for functional(ish) stuff, and isn't so helpful at mutating existing data structures. Which is a good thing. So if you wanted to produce a new array of new objects, you'd go with something like:
var newItems = CartItems
.Select(i => CreateNewItemWithPrice(i, item.EffectivePrice ??
CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice))
.ToList();
In general, that's a very nice approach, since mutating data can cause an awful lot of bugs.

Categories