Run a method on all objects within a collection - c#

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.

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();
}
}

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.

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

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);
}

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());

Related

Should I replace these nested foreach loops with LINQ, and how?

I receive data from a service in the following format:
public class Foo
{
string Name;
}
public class Bar
{
int ID;
List<Foo> Foos;
}
public class Container
{
List<Bar> Bars;
}
I need to write a method that returns the Names of all of the Foos in a Container, paired with the ID of their associated Bar, in the following class:
public class FooBar
{
int BarID;
Foo Name;
}
This is what I came up with:
IEnumerable<FooBar> FooBars(Container c)
{
foreach (var b in c.Bars)
{
foreach (var f in b.Foos)
{
yield return new FooBar() { BarID = b.ID; Name = f.Name; }
}
}
}
I have two questions:
How would I write this with LINQ instead of nested foreach loops?
Is there any good reason to do so?
This is the query syntax for LINQ's SelectMany, which allows you to do what you're describing. As far as why you would do this, I personally find it more easily readable.
from b in c.Bars
from f in b.Foos
select new FooBar {BarID = b.ID, Name = f.Name};

How to modify some elements of a list using linq in C#?

I have this class:
public class Document
{
public string ID { get; set; }
public string Type { get; set; }
public bool Checked {get;set; }
}
I create a set of 10 elements using Enumerable.Repeat static method:
var list = Enumerable.Repeat<Document>(
new Document
{
ID="1",
Type ="someType"
Checked = true
}, 10).ToList<Document>();
These creates 10 Documents all with the same properties. I need that some of them, for instance, the first 5 elements of the list list have the Checked property to false.
How can I achieve it, using as possible linq?
Note that your original sample has a bug because it's creating a 10 element List<Document> that only has 1 actual Document object. Here is a better way of doing it
Enumerable
.Range(1, 10)
.Select(i =>
new Document() {
ID = "1",
Type = "someType",
Checked = i <= 5
})
.ToList();
EDIT
Changed the code to be simpler. My original response was to editing an already existing list for which the following can be done
list.Take(5).ForEach(x => { x.Checked = false });
Note that you may have to define a simple ForEach method for this operation. If you don't have one defined here is an example
static class Extensions {
internal static void ForEach<T>(this IEnumerable<T> e, Action<T> action) {
foreach (var item in e) {
action(item);
}
}
}
Alternate idea to accomplish what you're asking for (also populates your ID column with something other than "1"):
var list = Enumerable.Range(1, 10)
.Select(i => new Document
{
ID = i.ToString(),
Type = "someType",
Checked = (i > 5)
}).ToList();

Get to next element in List

If i have a list of objects and i want to move to the next node with each function call (ie create a "GetNextNode" how would i go about doing this? Right now i have one method which will get the first node of my List and set the currentObj to it and return it (leaving previous node still at null) a flag indicates that we're not dealing with the first node in the list anymore. then i move forward and i want to iterate through the list (using foreach i guess?) to one node past my currentObj. Here is my code:
List<Employee> ListOfEmployees = new List<Employee>();
Employee currEmployeeObj = null;
Employee prevEmployeeObj = null;
foreach (Employee employee in ListOfEmployees)
{
//how do i keep track of the previous and current employee in here?
}
return (currEmployeeObj);
}
I hate to sound like a dinosaur, but since you're implementing with a List anyway, why not iterate over it with for instead of foreach? Integers are really useful for comparisons like i == j + 1
Looks like you really are re-inventing an enumerator:
public IEnumerator<Employee> GetEmployees()
{
foreach (Employee employee in ListOfEmployees)
{
//custom processing here
yield return employee;
}
}
Usage:
var myEnumerator = foo.GetEmployees();
while(myEnumerator.MoveNext())
{
var someEmployee = myEnumerator.Current;
//do something
}
Just as an update here is the full class implementation so you can verify it compiles and works..
public class Foo
{
List<Employee> ListOfEmployees = new List<Employee>();
public Foo()
{
ListOfEmployees.Add(new Employee());
}
public IEnumerator<Employee> GetEmployees()
{
foreach (Employee employee in ListOfEmployees)
yield return employee;
}
}
(As an academic exercise, the other answers are probably more appropriate here: )
You could create an extension method like so:
public static IEnumerable<Tuple<T, T>> ToPairs<T>(this IEnumerable<T> enumerable)
{
using (var enumerator = enumerable.GetEnumerator())
{
if (enumerator.MoveNext())
{
var previous = enumerator.Current;
while (enumerator.MoveNext())
{
var current = enumerator.Current;
yield return new Tuple<T, T>(previous, current);
previous = current;
}
}
}
}
To return you a tuple containing pairs of elements.
Which would be used like:
foreach (var pair in ListOfEmployees.ToPairs())
{
Employee prevEmployee = pair.Item1;
Employee currEmployeeObj = pair.Item2;
}
http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.aspx
The link above this line of text has what will work to solve my issue.
Thanks all for the responses and help! Upvoted those who tried to help and had something to offer

Simple question: Reflections in C#

I am learning the reflections concepts in c#. I have a class like this
public class pdfClass
{
public List<AttributeProperties> TopA { get; set; }
public List<AttributeProperties> TopB { get; set; }
public List<AttributeProperties> TopC { get; set; }
}
In another class I would like to extract the values from the list. I have stupid ways to do it like
public void ExtractValue (pdfClass incomingpdfClass, string type)
{
switch (type)
{
case "TopA":
foreach (var listitem in incomingPdfClass.TopA)
{...}
breaks;
case "TopB":
foreach (var listitem in incomingPdfClass.TopB)
{...}
breaks;
...
}
}
The operations in the foreach loops are similar. How can I do this in a clear way by using reflections?
public void ExtractValue(pdfClass incomingpdfClass, string type)
{
PropertyInfo pinfo = typeof(pdfClass).GetProperty("Top" + type);
var yourList = pinfo.GetValue(incomingpdfClass);
foreach (var listitem in yourList)
{ ... }
}
This is how you should do this using reflection. However, you should note that my code differs from yours in the fact that you are writing code that isn't clear nor would it compile. AS
public class ExtractValue (pdfClass incomingpdfClass, string type)
is non valid C# syntax if that is supposed to be a function as per my example this will work for you
Or if this is supposed to happen in the Constructor for the class it should look as follows
public class ExtractValue
{
public ExtractValue(pdfClass incomingpdfClass, string type)
{
PropertyInfo pinfo = typeof(pdfClass).GetProperty("Top" + type);
var yourList = pinfo.GetValue(incomingpdfClass);
foreach (var listitem in yourList)
{ ... }
}
}
var property = this.GetType().GetProperty(type);
foreach (var item in (List<AttributeProperties>)property.GetValue(this, null))
{
}
If you have instance of pdfClass you do not need to use reflection for accessing lists.
I would suggest to decouple type from strategy itself by persisting such a dictionary:
IDictionary<string, Func<pdfClass, AttributeProperties, bool>> strategy;
Once add relations like
strategy.Add("TopA", (pdf, item) =>
{
return pdf.TopA.IndexOf(item) >= 0;
});
and use like
string itemType = "TopA";
if (strategy.ContainsKey(itemType) )
{
bool found = strategy[itemType](incommingPdfClass, listItem);
}

How to refactor these generic methods?

UPDATE: I should have mentioned in the original post that I want to learn more about generics here. I am aware that this can be done by modifying the base class or creating an interface that both document classes implement. But for the sake of this exercise I'm only really interested in solutions that do not require any modification to the document classes or their base class. I thought that the fact that the question involves extension methods would have implied this.
I have written two nearly identical generic extension methods and am trying to figure out how I might refactor them into a single method. They differ only in that one operates on List and the other on List, and the properties I'm interested in are AssetID for AssetDocument and PersonID for PersonDocument. Although AssetDocument and PersonDocument have the same base class the properties are defined in each class so I don't think that helps. I have tried
public static string ToCSVList<T>(this T list) where T : List<PersonDocument>, List<AssetDocument>
thinking I might then be able to test the type and act accordingly but this results in the syntax error
Type parameter 'T' inherits
conflicting constraints
These are the methods that I would like to refactor into a single method but perhaps I am simply going overboard and they would best be left as they are. I'd like to hear what you think.
public static string ToCSVList<T>(this T list) where T : List<AssetDocument>
{
var sb = new StringBuilder(list.Count * 36 + list.Count);
string delimiter = String.Empty;
foreach (var document in list)
{
sb.Append(delimiter + document.AssetID.ToString());
delimiter = ",";
}
return sb.ToString();
}
public static string ToCSVList<T>(this T list) where T : List<PersonDocument>
{
var sb = new StringBuilder(list.Count * 36 + list.Count);
string delimiter = String.Empty;
foreach (var document in list)
{
sb.Append(delimiter + document.PersonID.ToString());
delimiter = ",";
}
return sb.ToString();
}
Your implementation is basically reimplementing string.Join method, so you might try to make it simpler and more generic with some LINQ:
public static string ToCSVList<T>(this IEnumerable<T> collection)
{ return string.Join(",", collection.Select(x => x.ToString()).ToArray()); }
public static string ToCSVList(this IEnumerable<AssetDocument> assets)
{ return assets.Select(a => a.AssetID).ToCSVList(); }
public static string ToCSVList(this IEnumerable<PersonDocument> persons)
{ return persons.Select(p => p.PersonID).ToCSVList(); }
I think the way would be to let PersonDocument and AssetDocument inherit from a Document class, which would have an Id property, that stores your current PersonId or AssetId respectivly.
Make an abstraction, such as IDocument or an abstract class BaseDocument which exposes the id (which is the only field you are really using) and make both PersonDocument and AssetDocument implement that. Now make your generic method accept IDocument or BaseDocument instead.
How do you like this variant (a little bit simplified, but you should get the idea):
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
var la = new List<AssetDocument> { new AssetDocument() {AssetID = 1} };
var result = la.ToCSVList(l => l.AssetID.ToString());
}
}
public class AssetDocument
{
public int AssetID { get; set; }
}
public static class GlobalExtensions
{
public static string ToCSVList<T>(this List<T> list, Func<T, string> propResolver)
{
var sb = new StringBuilder(list.Count * 36 + list.Count);
var delimiter = "";
foreach (var document in list)
{
sb.Append(delimiter);
sb.Append(propResolver(document));
delimiter = ",";
}
return sb.ToString();
}
}
}
This would work with any list (in case you don't care about the preallocated memory in StringBuilder even with any IEnumerable).
Update: Even if you want to keep your original extension methods, you can reduce them to one line of code with this.
What about making your method also take in a delegate to return the document.AssetID.ToString() for that list as appropriate?
Using Lamda expressions this could be reasonably lightweight, if a little ugly. A console application to demonstarate:
class Program
{
static void Main(string[] args)
{
List<string> strings = new List<string> { "hello", "world", "this", "is", "my", "list" };
List<DateTime> dates = new List<DateTime> { DateTime.Now, DateTime.MinValue, DateTime.MaxValue };
Console.WriteLine(ToCSVList(strings, (string s) => { return s.Length.ToString(); }));
Console.WriteLine(ToCSVList(dates, (DateTime d) => { return d.ToString(); }));
Console.ReadLine();
}
public static string ToCSVList<T, U>(T list, Func<U, String> f) where T : IList<U>
{
var sb = new StringBuilder(list.Count * 36 + list.Count);
string delimiter = String.Empty;
foreach (var document in list)
{
sb.Append(delimiter + f(document));
delimiter = ",";
}
return sb.ToString();
}
}
Whether this is the best approach or not, I leave as an exercise for the reader!
I only know java, so I can't give correct syntax, but the general approach should work:
define an interface Document, which gets implemented by PersonDocument and AssetDocument,
with the method
String getIdString();
Use a List as a parameter to you method. Note this is java syntax for a List of Something that inherits/extends from Document.
You could use Reflection for a bit of Duck Typing action!
I have assumed that your classes are called #class#Document and you want to concatenate the #class#ID properties. If the list contains classes that conform to this naming they will be concatenated. Otherwise they wont.
This is very much how the Rails framework operates, using Convention over Configuration.
Obviously such behaviour is more suited to dynamic languages such as Ruby. Probably the best solution for a more static language such as C# would be to refactor the base classes, use interfaces etc.. But that wasnt in the spec, and for educational purposes this is one way around things!
public static class Extensions
{
public static string ToCSVList<T> ( this T list ) where T : IList
{
var sb = new StringBuilder ( list.Count * 36 + list.Count );
string delimiter = String.Empty;
foreach ( var document in list )
{
string propertyName = document.GetType ().Name.Replace("Document", "ID");
PropertyInfo property = document.GetType ().GetProperty ( propertyName );
if ( property != null )
{
string value = property.GetValue ( document, null ).ToString ();
sb.Append ( delimiter + value );
delimiter = ",";
}
}
return sb.ToString ();
}
}
Usage (note no need for inheritance with Duck Typing - also works with any type!) :
public class GroovyDocument
{
public string GroovyID
{
get;
set;
}
}
public class AssetDocument
{
public int AssetID
{
get;
set;
}
}
...
List<AssetDocument> docs = new List<AssetDocument> ();
docs.Add ( new AssetDocument () { AssetID = 3 } );
docs.Add ( new AssetDocument () { AssetID = 8 } );
docs.Add ( new AssetDocument () { AssetID = 10 } );
MessageBox.Show ( docs.ToCSVList () );
List<GroovyDocument> rocs = new List<GroovyDocument> ();
rocs.Add ( new GroovyDocument () { GroovyID = "yay" } );
rocs.Add ( new GroovyDocument () { GroovyID = "boo" } );
rocs.Add ( new GroovyDocument () { GroovyID = "hurrah" } );
MessageBox.Show ( rocs.ToCSVList () );
...

Categories

Resources