Reputation: 10865
So I have a collection of Razzies created from a Collection of Bloops. I retrieve this collection using a Linq query. Reference:Linq Select Certain Properties Into Another Object? for the query.
I would like to know if it is possible to run a method on all of the newly created Razzies before returning the collection, or even right after, just without using a for-loop.
I tried this:
Dim results = From item In bloops _
Select New Razzie() With _
{ _
.FirstName = item.FirstName, _
.LastName = item.LastName _
}.UpdateAddress(item.Address)
But it returns nothing.
Upvotes: 0
Views: 3301
Reputation: 20777
If you're looking to abstract away the foreach loop, I'd just write an extension method for IEnumerable<T> that duplicates List<T>'s ConvertAll and ForEach methods, like this:
public static IEnumerable<TOutput> ConvertAll<T, TOutput>(this IEnumerable<T> collection, Converter<T, TOutput> converter)
{
if (converter == null)
throw new ArgumentNullException("converter");
List<TOutput> list = new List<TOutput>();
foreach (T item in collection)
{
list.Add(converter(item));
}
return list;
}
public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
{
foreach (T item in collection)
{
action(item);
}
}
Then you could just call something like:
bloops
.ConvertAll(bloop => new Razzie()
{
FirstName = bloop.FirstName,
Lastname = bloop.LastName
})
.ForEach(razzie => razzie.UpdateAddress());
Upvotes: 0
Reputation: 33010
Why not just do this the normal, unconvaluted way? You can do a bunch of fancy stuff with extension methods...but your likely breaking the purity rule by performing an update with an extension method...and it makes things difficult to understand too. Try this:
var results = from ... select new { Address = item.Address, Razzie = new Razzie { ... }}
foreach (var result in results)
{
result.Razzie.UpdateAddress(result.Address);
}
Upvotes: 0
Reputation: 6947
Russ, this might do what you want. It's a pretty simple approach. If this is not what you want, please expand your question.
This will run the method on each element as you enumerate over them. It will not run the method until you enumerate, but you can safely know that the method will run before you use the data.
EDIT Since you are using a sealed 3rd party class, use extension methods. That's what they're for. ;) Modified code to use extension methods.
class MyArgs { }
class Razzie //pretend this is a 3rd party class that we can't edit
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
static class RazzieExtensions
{
public static Razzie MyMethod(this Razzie razzie, MyArgs args)
{
razzie.FirstName = razzie.FirstName.ToUpper();
return razzie;
}
}
class Program
{
static void Main(string[] args)
{
var bloops = new List<Razzie>
{
new Razzie{FirstName = "name"},
new Razzie{FirstName = "nAmE"}
};
var myArgs = new MyArgs();
var results = from item in bloops
select new Razzie
{
FirstName = item.FirstName,
LastName = item.LastName
}.MyMethod(myArgs);
foreach (var r in results)
Console.WriteLine(r.FirstName);
Console.ReadKey();
}
}
Upvotes: 2
Reputation: 72015
Using a foreach loop after your initial processing is the normal way to do this. If you don't want to use a foreach loop, you'll need to define your own extension method to handle this situation.
Upvotes: 1
Reputation: 755457
I'm not sure what you mean by RunVoid. Void suggests no return yet you assign the results to a value.
Do you RunVoid to execute a method on every item and then return the original collection? If so, there is no built-in method but you can add one like so.
<Extension>
Public Function RunVoid(Of T)(source As IEnumerable(Of T), del As Action(Of T) As IEnumerable(Of T)
For Each cur in source
del(cur)
Next
return source
End Function
Upvotes: 0