I have this two foreach loops to get all the attributes, linearly, of one my class.
foreach (PropertyInfo property in GetType().GetProperties())
{
foreach (Attribute attribute in property.GetCustomAttributes(true))
{
}
}
How I can simplify this two loops to one loop or to linq operation to get the class attributes ?
You can rely on SelectMany()
var attributes = GetType().GetProperties()
.SelectMany(p => p.GetCustomAttributes(true));
foreach (var attribute in attributes)
{
// Code goes here
}
Or using query notation:
var attributes=from p in yourObject.GetType().GetProperties()
from a in p.GetCustomAttributes(true)
select a;
Related
How do I create LINQ to call DoSomething() only once to reduce these duplicate codes? Note that there are some properties in nameValue which I don't need to do anything about it. DoSomething() is only applied for these 4 properties.
foreach (var nameValue in nameDetails.NameValue)
{
if (nameValue.FirstName != null)
{
DoSomething(nameValue.FirstName)
}
if (nameValue.MaidenName != null)
{
DoSomething(nameValue.MaidenName)
}
if (nameValue.MiddleName != null)
{
DoSomething(nameValue.MiddleName)
}
if (nameValue.Surname != null)
{
DoSomething(nameValue.Surname)
}
}
Move the condition into the function and you can write
foreach (var nameValue in nameDetails.NameValue)
{
DoSomethingMaybe(nameValue.FirstName);
DoSomethingMaybe(nameValue.MaidenName);
DoSomethingMaybe(nameValue.MiddleName);
DoSomethingMaybe(nameValue.Surname);
}
void DoSomethingMaybe(string value)
{
if (value != null)
{
DoSomething(value)
}
}
perfectly readable and no unnecessary overhead, no throwaway objects. Maybe not the answer you expect, but LINQ is not magic, that makes things better just be being there.
You may create an array of *names, then use SelectMany to flatten 2 dimensional array into IEnumerable<string> , e.g.:
var enumerable = nameDetails.NameValue.SelectMany(elem => new[]
{
elem.FirstName,
elem.MaidenName,
elem.MiddleName,
elem.Surname
}).Where(value => value != null);
foreach (var value in enumerable)
{
DoSomething(value);
}
My interpretation of your question is that you want to write DoSomething only once but still want to perform it more than once if more than one name part is not null.
You can refactor your code to this:
var names = nameDetails.NameValue
.SelectMany(nv => new string[] { nv.FirstName, nv.MaidenName, nv.MiddleName, nv.Surname })
.Where(name => name != null);
foreach (var name in names)
{
DoSomething(name);
}
This makes use of SelectMany which allows each item of the source enumerable to be mapped into multiple values which are then flattened into an enumerable of the mapped element value's type.
what I want to do is to add for example class in IEnumerable after specific check
public static IEnumerable<T> GroupBy<T, O> (this IEnumerable<T> list, Func<T, O> filter)
{
List<IEnumerable<T>> grouped = new List<IEnumerable<T>>();
foreach (var item in list)
{
foreach (var g in grouped)
{
foreach (var p in g)
{
if (filter(p).Equals(filter(item)))
{
// Add item to g
}
}
}
}
}
Is something like this possible in foreach?
No, that's not possible: every time you change source collection, foreach has to be started anew. You'll need to have a separate collection for intermediate accumulation, then join that collection with grouped.
Also, your algorithms doesn't work correctly: the second foreach will never start working as on the first iteration there will be no items in grouped collection. So you will just iterate list without applying any logic to its elements.
I want to get the properties of the properties of a class.
What I have right now:
foreach (var v in test.GetType().GetProperties())
{
foreach (var p in v.GetType().GetProperties())
{
}
}
The first foreach loop works fine and gets the properties of the class variable test. However, in the second loop, I get output such as MemberType, ReflectedType, Module etc.. not actual properties.
My goal is to get the properties of the properties of a class and then edit their value (truncate them using another function).
Thanks.
On the second loop GetType() returns a PropertyInfo object. You have to get the propertyType of v as v.PropertyType.GetProperties() to achieve what you want.
So, the code should be:
foreach (var v in test.GetType().GetProperties())
{
foreach (var p in v.PropertyType.GetProperties())
{
// Stuff
}
}
The type returned by v.GetType() is that of PropertyInfo, because v is a property info. You don't want the properties of the PropertyInfo type, you want the properties of the type itself.
Use v.PropertyType, not v.GetType().
GetProperties() gets you PropertyInfo objects which tell you information about the properties of the object. You need to use GetValue to actually get the values of those properties. From there you can repeat the process to get the values of that object's properties.
foreach (var v in test.GetType().GetProperties())
{
var propertyValue = v.GetValue(test);
foreach (var p in propertyValue.GetType().GetProperties())
{
var subPropertyValue = p.GetValue(propertyValue);
Console.WriteLine("{0} = {1}", p.Name, subPropertyValue);
}
}
After editing the value use SetValue to persist it back to the object.
I have these two clases:
public class Client{
public List<Address> addressList{get;set;}
}
public class Address{
public string name { get; set; }
}
and I have a List of type Client called testList. It contains n clients and each one of those contains n addresses
List<Client> testList;
how can i do the following using LINQ:
foreach (var element in testList)
{
foreach (var add in element.addressList)
{
console.writeLine(add.name);
}
}
Well I wouldn't put the Console.WriteLine in a lambda expression, but you can use SelectMany to avoid the nesting:
foreach (var add in testList.SelectMany(x => x.addressList))
{
Console.WriteLine(add.name);
}
I see little reason to convert the results to a list and then use List<T>.ForEach when there's a perfectly good foreach loop as part of the language. It's not like you naturally have a delegate to apply to each name, e.g. as a method parameter - you're always just writing to the console. See Eric Lippert's blog post on the topic for more thoughts.
(I'd also strongly recommend that you start following .NET naming conventions, but that's a different matter.)
foreach(var a in testList.SelectMany(c => c.addressList))
{
Console.WriteLine(a.name);
}
It will not materialize any new collection.
This may helps:
testList.ForEach(i => i.addressList.ForEach(j => Console.WriteLine(j.name)));
foreach(var add in testList.SelectMany(element => element.addressList)){
Console.WriteLine(add.name);
}
testList.SelectMany(c => c.addressList)
.Select(a => a.name)
.ToList()
.ForEach(Console.WriteLine)
Use the ForEach method:
testList.ForEach(tl=>tl.addressList.ForEach(al=>console.writeLine(al.name)));
LINQ doesn't include a ForEach function, and they don't intend to, since it goes against the idea of LINQ being functional methods. So you can't do this in a single statement. List<T> has a ForEach method, but I'd recommend not using this for the same reasons that it's not in LINQ.
You can, however, use LINQ to simplify your code, e.g.
foreach (var add in testList.SelectMany(x => x.addressList))
{
Console.WriteLine(add.name);
}
// or
foreach (var name in testList.SelectMany(x => x.addressList).Select(x => x.name))
{
Console.WriteLine(name);
}
I've got a nested foreach loop that I really need to cut the computation time on. Each collection is at about 50 members, so the extrapolation is huge. I've looked at a lot of information about SelectMany, but I'm still not entirely sure how to use it, or if it's the correct solution.
List<string> StringList; //Populated in previous code
Type[] assemblyTypes = RandomAssembly.GetTypes();
foreach (String name in StringList)
{
foreach (Type at in assemblyTypes)
{
if (name == at.Name)
{
//Do stuff.
}
}
}
Thanks in advance!
Use a lookup (such as a dictionary) to increase the speed of checking for a type name:
List<string> StringList; //Populated in previous code
Dictionary<string,Type> assemblyTypes = RandomAssembly.GetTypes()
.ToDictionary(t => t.Name, t => t);
foreach (String name in StringList)
{
if (assemblyTypes.ContainsKey(name))
{
//Do stuff.
}
}
}
You should also check which of the 2 collections (StringList or assemblyTypes) is likely to be larger. You generally want the larger one to be converted to the lookup in order to reduce the number of iterations.
Load Type[] into a Dictionary or HashSet (depending on your version of .NET) and then the inner loop disappears.
List<string> StringList; //Populated in previous code
Type[] assemblyTypes = RandomAssembly.GetTypes();
Dictionary<String,Type> typesHash = new Dictionary<String,Type>();
foreach ( Type type in assemblyTypes ) {
typesHash.Add( type.Name, type );
}
foreach (String name in StringList) {
Type type = null;
if ( typesHash.TryGetValue( name, out type ) ) {
// do something with type
}
}
You might try something like:
assemblyTypes.Where(x => StringList.Contains(x.Name));
Keep in mind this is case sensitive and ignores whitespace, so you will need to add case consideration or trimming if that's an issue.
Edit: (example for loop usage)
foreach (Type item in assemblyTypes.Where(x => StringList.Contains(x.Name)))
{
// Do stuff
}
If your array/list contains lots of items , you can try using Parallel ForEach loop.
The best optimization might be by querying not for the name but instead for an implemented interface.
Make sure you are optimizing the correct issue/part of your code.