C# Foreach (Property in Object)... Is There a Simple Way of Doing This

c# foreach (property in object)... Is there a simple way of doing this?

Give this a try:

foreach (PropertyInfo propertyInfo in obj.GetType().GetProperties())
{
// do stuff here
}

Also please note that Type.GetProperties() has an overload which accepts a set of binding flags so you can filter out properties on a different criteria like accessibility level, see MSDN for more details: Type.GetProperties Method (BindingFlags) Last but not least don't forget to add the "system.Reflection" assembly reference.

For instance to resolve all public properties:

foreach (var propertyInfo in obj.GetType()
.GetProperties(
BindingFlags.Public
| BindingFlags.Instance))
{
// do stuff here
}

Please let me know whether this works as expected.

How can you loop over the properties of a class?

Sure; you can do that in many ways; starting with reflection (note, this is slowish - OK for moderate amounts of data though):

var props = objectType.GetProperties();
foreach(object obj in data) {
foreach(var prop in props) {
object value = prop.GetValue(obj, null); // against prop.Name
}
}

However; for larger volumes of data it would be worth making this more efficient; for example here I use the Expression API to pre-compile a delegate that looks writes each property - the advantage here is that no reflection is done on a per-row basis (this should be significantly faster for large volumes of data):

static void Main()
{
var data = new[] {
new { Foo = 123, Bar = "abc" },
new { Foo = 456, Bar = "def" },
new { Foo = 789, Bar = "ghi" },
};
string s = Write(data);
}
static Expression StringBuilderAppend(Expression instance, Expression arg)
{
var method = typeof(StringBuilder).GetMethod("Append", new Type[] { arg.Type });
return Expression.Call(instance, method, arg);
}
static string Write<T>(IEnumerable<T> data)
{
var props = typeof(T).GetProperties();
var sb = Expression.Parameter(typeof(StringBuilder));
var obj = Expression.Parameter(typeof(T));
Expression body = sb;
foreach(var prop in props) {
body = StringBuilderAppend(body, Expression.Property(obj, prop));
body = StringBuilderAppend(body, Expression.Constant("="));
body = StringBuilderAppend(body, Expression.Constant(prop.Name));
body = StringBuilderAppend(body, Expression.Constant("; "));
}
body = Expression.Call(body, "AppendLine", Type.EmptyTypes);
var lambda = Expression.Lambda<Func<StringBuilder, T, StringBuilder>>(body, sb, obj);
var func = lambda.Compile();

var result = new StringBuilder();
foreach (T row in data)
{
func(result, row);
}
return result.ToString();
}

Is there a way of restricting a foreach loop thorugh a class's properties in C#?

No, regions are not available at runtime.

You can for instance create an attribute and use it on the properties that you want to iterate.

[AttributeUsage(AttributeTargets.Property)]
public class ReflectThisAttribute : Attribute
{
}

And use it like this:

[ReflectThis]
public bool HAS_POSITION { get; set; }

[ReflectThis]
public bool HAS_SOURCE { get; set; }

[ReflectThis]
public bool HAS_DESTINATION { get; set; }

[ReflectThis]
public bool HAS_SUBJECT { get; set; }

Which enables you to:

public void FillFlags( int combinedFlags )
{
foreach (PropertyInfo prop in GetType().GetProperties() )
{
if (prop.GetCustomAttribute<ReflectThisAttribute> == null)
continue;

// Only get here if the property have the attribute
}
}

You could also check if it's a bool:

public void FillFlags( int combinedFlags )
{
foreach (PropertyInfo prop in GetType().GetProperties() )
{
if (prop.PropertyType != typeof(bool))
continue;

// Only get here if the property is a bool
}
}

However!

Since it looks like the FillFlags method is part of the class that you want to change I would recommend that you assign the properties manually in it. The code will become much more readable than trying to use reflection.

Reflection is typically used to generalize solutions. For instance:

[AttributeUsage(AttributeTargets.Property)]
public class FlagValueAttribute : Attribute
{
public FlagValueAttribute (int value)
{
Value = value;
}

public int Value{get;set}
}

public class SomeEntity
{

[FlagValue(1)]
public bool HAS_POSITION { get; set; }

[FlagValue(2)]
public bool HAS_SOURCE { get; set; }

[FlagValue(4)]
public bool HAS_DESTINATION { get; set; }

[FlagValue(8)]
public bool HAS_SUBJECT { get; set; }
}

public static class EntityExtensions
{

public static void FillFlags(this object instance, int combinedFlags )
{
foreach (PropertyInfo prop in instance.GetType().GetProperties() )
{
var attr = prop.GetCustomAttribute<FlagValueAttribute>();
if (attr == null)
continue;

if ((attr.Value & combinedFlags) != 0)
prop.SetValue(instance, true);
}
}
}

Usage:

var myEntity = new SomeEntity();

// will set HAS_SOURCE and HAS_SUBJECT to true
myEntity.FillFlags(10);

C# Set property of object while iterating on it in list

This is because Point is not a reference type (it's a struct not a class). So the point variable in the foreach is not actually a reference to the original Point, it is a copy. The compiler doesn't let you modify it because (I assume) it would be easy to think you're changing the original when you are not.

I'm not sure if there's a better way but you could get around this by doing something like this:

for (int i = 0; i < filledPoints.Count; i++)
{
Point temp = filledPoints[i];
temp.X = 10;
filledPoints[i] = temp;
}

C# Enumerating Object foreach

Your solar system doesn't tell it can iterate over anything. You have to implement IEnumerable to tell the compiler that:

public class SolarSystem : IEnumerable<Planet>
{
public IEnumerator<Planet> GetEnumerator()
{
yield return mercury;
yield return venus;
}

IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}

This is a basic implementation of an enumerable. It uses the yield keyword to generate an enumerator for you on the fly.

Optionally, you could create a property Planets in your class, probably something like this:

List<Planet> Planets {get;} = List<Planet>();

Then you can iterate over solarSystem.Planets.

C# calling all properties, for each loop

you need to use reflection to be able to loop over each property dynamically, personally i wont change it to use reflection since reflection has performance penalties, but here is the code for your reference:

Change Class fields to properties:

    public class Person
{
public string firstname {get;set;}
public string surname {get;set;}
public string haircolor {get;set;}
public string eyecolor {get;set;}
public string weight {get;set;}
public string height {get;set;}
public string age {get;set;}
}

Write this code in your main method:

       Person addperson = new Person();
PropertyInfo[] props = addperson.GetType().GetProperties();

foreach(PropertyInfo prop in props)
{
Console.WriteLine("Please enter " + prop.Name.ToString());
string input = Console.ReadLine();
prop.SetValue(addperson, input, null);
}

EDIT:

This line of code:

 PropertyInfo[] props = addperson.GetType().GetProperties();

Returns all the public properties of the Person type (class), then each PropertyInfo object discovers the attributes of the property and provides access to its metadata.

Why is this foreach loop missing a property from the class?

First of all, good job on linking the code sample. Without that, I would have passed by this question in about three seconds. :D

In GetAllProperties(), your entire loop is inside a giant try catch block, where the catch returns the dictionary as it is so far, without checking what the exception is. So if you don't get everything you expect, you've probably hit an error.

Amend the catch block:

catch (Exception ex) { Console.WriteLine(ex.ToString()); return result; }

Now, you can see the problem:

System.ArgumentException: An item with the same key has already been added. Key: Test

Your object has more than one property named "Test," but Keys in a Dictionary must be unique.

Summary: Errors aren't the enemy, they're your best friend. Don't use try / catch to bypass errors. If you do, you may get "mysterious, never seen that happen before!" results.



Related Topics



Leave a reply



Submit