How do I loop through all fields in an object in C#? - c#

I have an object like this:
public class Filters {
public int var1 = 1,
var2 = 2,
var3 = 3;
}
I declare this object here:
Filters filter1 = new Filters();
And I want to access var1, var2, and var3 in a loop and do something with it. i.e.:
foreach (var prop in filter1.props) {
Console.WriteLine(filter1[prop] + 3);
}
and the output would be:
4
5
6
I imagine I need to do a foreach loop for each property using
foreach(PropertyInfo p in filter1.GetType().GetProperties()), but I don't know how to 1) loop through props var1, var2, var3, and 2) how to subset the prop from filter1 using the name stored in the variable

If you describe your variable as properties like bellow,
public class Filters
{
public int var1 { get; set; } = 1;
public int var2 { get; set; } = 2;
public int var3 { get; set; } = 3;
}
You can access these properties with
GetType().GetProperties()
then the main method will give you what you ask for
static void Main(string[] args)
{
Filters filter1 = new Filters();
foreach (var prop in filter1.GetType().GetProperties())
{
Console.WriteLine("{0}={1}", prop.Name, (int)prop.GetValue(filter1, null) + filter1.GetType().GetProperties().Length);
}
Console.ReadKey();
}
Result will be
4
5
6

Thanks to everyone who answered-- a couple hints helped me get there. I just started in C# so I didn't know what fields/props were, so thanks #SeM #John. But with that, and with answers by #Icepickle & #arslanaybars with GetProperties() but for fields instead:
FieldInfo[] fields = typeof(GeneralFilters).GetFields();
for (int i = 0; i < fields.Length; i++)
{
//MANIPULATE HERE
BlankTemplate tempFilter = (BlankTemplate)fields[i].GetValue(filters);
// Ignore this for now. tempFilter.selectedItems;
}
where BlankTemplate is defined here:
public class BlankTemplate
{
public string[] selectedItems;
public bool selectAll = false;
}
And now in tempFilter I have the object that I need to use at every iteration
Thanks!!!
Edit: I realize that this doesn't answer the question of how to subset using the stringified name of the object fields. What I envisioned before is generating array of field names, then looping through and subsetting the data in the fields using the field names, like in javascript:
var fieldNames = Object.keys(filterObject);
for (var i = 0; i < fieldNames.length; i++) {
doSomething( filterObject[fieldNames[i]] );
}
But it seems to be a bit different in C#

An alternative answer to your question could be the following, say you have a class of filters like the following
public class Filter
{
public IDictionary<string, object> Properties { get; } = new Dictionary<string, object>();
}
This would allow you to have a dynamic set of filters, you can assign new properties as a consumer and iterate the existing ones. That seems to fit your current requirements.
As for a real answer, as many in the comments have pointed out, if you want to iterate properties, then you should actually use them. In your sample code, you have provided fields instead.
So your class Filter would probably end up looking like this (note that I think var1...var3 are the most horrible names you can use as I cannot imagine what they might define in the end):
public class Filter
{
public int Var1 { get; set; } = 1;
public int Var2 { get; set; } = 2;
public int Var3 { get; set; } = 3;
}
and then you could have something similar like:
var filter = new Filter();
var filterType = filter.GetType();
var readableProperties = filterType.GetProperties().Where( p => p.GetGetMethod() != null );
foreach (var property in readableProperties)
{
var value = (int)property.GetValue( filter );
Console.WriteLine( $"{property.Name} = {value + 3}" );
}
To ensure that you only select those you actually want, you can ofcourse check the name if it equals to Var1, Var2, Var3 or matches a regex expression, or whatever you like to think of ;)
A sample of the code here, you can find in this dotnetfiddle (though without autoproperties and $)

Related

Is it possible to easily get variable names in a method as well as their values

Following my Is it possible to have a Function that takes any number of variables of any type?
I have the function that gets any number of any type of variables and it works perfectly
public string funcVars(params object[] paths)
{
string strVars = String.Join(", ", paths.Select(x => x.ToString()));
return strVars;
}
To call it I'd simply need to
string someString ="asd"; int someInt = 123; bool someBool=false;
funcVars(someString,someInt,someBool);
And the output would be
asd,123,false
is there any simple way I can also get the variable names as well as their values, so the output would be
asd,123,false,someString,someInt,someBool //(or any other similar form)
Or do I need to hardcode the names every time I call my method ?
funcVars("someString","someInt","someBool",someString,someInt,someBool);
What you really should be doing is creating a class to hold your variables:
internal class MyValues
{
internal string SomeString { get; set; }
internal int SomeInt { get; set; }
internal bool SomeBool { get; set; }
}
Then you can pass an instance of your class:
var mv = new MyValues() { SomeString = "asd", SomeInt = 123, SomeBool = false };
funcVars(mv);
Here is funcVars:
public string funcVars(MyValues values)
{
string strVars =
String.Join(", ", new[] { values.SomeString,
values.SomeInt.ToString(), values.SomeBool.ToString() });
return strVars;
}
Straight up stealing roy.ap's code and adding the "nameof()" method since getting the name of the property seemed to be apart of the question.
class Program
{
internal class MyValues
{
internal string SomeString { get; set; }
internal int SomeInt { get; set; }
internal bool SomeBool { get; set; }
}
static void Main(string[] args)
{
var mv = new MyValues() { SomeString = "asd", SomeInt = 123, SomeBool = false };
Console.WriteLine(funcVars(mv));
Console.ReadLine();
}
public static string funcVars(MyValues values)
{
string strVars =
String.Join(", ", new[]
{
nameof(values.SomeString), values.SomeString,
nameof(values.SomeInt), values.SomeInt.ToString(),
nameof(values.SomeBool), values.SomeBool.ToString()
});
return strVars;
}
}
There really isn't a way to get the variable names via the the function itself because the scope changes once you're in the method. That is even if you pass an array of objects, if you perform a foreach to go through each object you will give the individual objects a new scope specific name.
No, because the variables are not actually passed
No it is not possible, because the variables themselves are not actually passed. Their values are passed.
Consider this code:
string someString ="asd"; int someInt = 123; bool someBool=false;
funcVars(someString,someInt,someBool);
In your call to funcVars, all the parameters are passed by value. All three variables are copied, and copy of them is put on the stack. These stack variables are identified by completely different symbols-- (e.g. paths[0],paths[1], etc.)
After all, what would happen if you called it like this?
funcVars("Hello",245+25,test != null);
Obviously those values do not have variable names. There is no way your function can possibly retrieve what doesn't exist.
Use ExpandoObject instead
The System.Dynamic.ExpandoObject seems like a really good fit for this problem.
var args = new System.Dynamic.ExpandoObject();
args.SomeString = "hello";
args.SomeInt = 32;
args.SomeBool = false;
funcVars(args);
public static string funcVars(ExpandoObject inputs)
{
var sb = new StringBuilder();
foreach (KeyValuePair<string, object> kvp in inputs)
{
sb.Append(String.Format("{0} = {1}", kvp.Key, kvp.Value);
}
return sb.ToString();
}

Sum up all the properties of a collection and dynamically assigned it to another object

I have a collection of object in lst of type DataResponse and what I would like to do is sum up all the properties that are int and decimal of this collection and assign the result of each property to another object DataContainerResponse that has the same exact property names(and types) as the those that are being summed up.
I can do this manually by typing out each property by hand and do a .Sum(s=>s.<propertyname>. But that so 90s. Below is my fruitless attempt to juice it out. Frankly, I never assigned a var to a lambda expression before and I don't even know if it's possible .Sum(s=><var name>);
public DataAggragationResponse doAggregation(List<DataResponse> lst)
{
if (lst.Count == 0)
return null;
DataContainerResponse rd = new DataContainerResponse();
//If I do it manually typing each prop by hand.
rd.VIOL = lst.Sum(s => s.VIOL);
//Automation!!!
foreach (PropertyInfo propertyInfo in typeof(DataResponse).GetProperties())
{
rd.GetType().GetProperties().SetValue(lst.Sum(s => propertyInfo.Name[0]));
}
}
If you want to go with full reflection, you can try something like the following. I didnt optimize the code, did it as fast as I can. So sorry for the messy look and Im assuming the property names are same in the aggregated result class and the unit class that you are aggregating against.
class Program
{
static void Main(string[] args)
{
var list = new List<DataResponse>();
list.Add(new DataResponse() { Stuff = 1, Stuff2 = 2 });
list.Add(new DataResponse() { Stuff = 1, Stuff2 = 2 });
Stopwatch watch = new Stopwatch();
watch.Start();
var response = DoAggregationReflection(list);
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalMilliseconds);
watch.Reset();
watch.Start();
var response2 = DoAggregation(list);
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalMilliseconds);
}
public static DataAggragationResponse DoAggregationReflection(List<DataResponse> lst)
{
if (lst.Count == 0)
return null;
DataAggragationResponse aggrResponse = new DataAggragationResponse();
var responseType = typeof(DataResponse);
var aggrResponseType = typeof(DataAggragationResponse);
foreach (PropertyInfo propertyInfo in typeof(DataResponse).GetProperties())
{
aggrResponseType.GetProperty(propertyInfo.Name).SetValue(aggrResponse, lst.Sum(x => (int)responseType.GetProperty(propertyInfo.Name).GetValue(x)));
}
return aggrResponse;
}
public static DataAggragationResponse DoAggregation(List<DataResponse> lst)
{
if (lst.Count == 0)
return null;
DataAggragationResponse aggrResponse = new DataAggragationResponse();
aggrResponse.Stuff = lst.Sum(x => x.Stuff);
aggrResponse.Stuff2 = lst.Sum(x => x.Stuff2);
return aggrResponse;
}
}
public class DataResponse
{
public int Stuff { get; set; }
public int Stuff2 { get; set; }
}
public class DataAggragationResponse
{
public int Stuff { get; set; }
public int Stuff2 { get; set; }
}
But, as a suggestion, if you want to go with this approach, its better if you can cache all the reflection invokes you're making as they are costly. And the 90's approach would still win in benchmark. Like the example above would benchmark like the following with the simple StopWatch.
1.8193
0.4476
Press any key to continue . . .
The first one is the execution time of DoAggregationReflection and the last one is the execution time of DoAggregation. You can optimize the reflection one as much as you want but I think it would still fail to compete with the basic one.
Sometime's the 90's are way better. ;) Although you'd still use LINQ to do the actual summation so that's not that 90's anymore as LINQ was born in 2007 according to wikipedia.
Hopefully this can help you. I wish I had kept the SO link to the question I pulled this from a while ago. Sorry to the original poster for not mentioning his/her name.
using System.Reflection;
public static Dictionary<string, string> GetPropertiesValue(object o)
{
Dictionary<string, string> PropertiesDictionaryToReturn = new Dictionary<string, string>();
foreach (MemberInfo itemMemberInfo in o.GetType().GetMembers())
{
if (itemMemberInfo.MemberType == MemberTypes.Property)
{
//object PropValue = GetPropertyValue(OPSOP, item.Name);
//string itemProperty = itemMemberInfo.Name;
//string itemPropertyValue = o.GetType().GetProperty(itemMemberInfo.Name).GetValue(o, null).ToString();
//Console.WriteLine(itemProperty + " : " + itemPropertyValue);
PropertiesDictionaryToReturn.Add(itemMemberInfo.Name, o.GetType().GetProperty(itemMemberInfo.Name).GetValue(o, null).ToString());
}
}
return PropertiesDictionaryToReturn;
}
It's not exactly what you need but, I think you could adapt it.
I would rather take a different approach. I would dynamically build and compile (once) something like this:
Func<DataContainerResponse, DataResponse, DataContainerResponse> aggregateFunc =
(result, item) =>
{
result.Prop1 += item.Prop1;
result.Prop2 += item.Prop2;
...
result.PropN += item.PropN;
return result;
}
(if you wonder why the signature is like the above, the answer is - because it can be used directly for the following Aggregate overload).
Here is how it can be done:
static readonly Func<DataContainerResponse, DataResponse, DataContainerResponse>
AggregateFunc = BuildAggregateFunc();
static Func<DataContainerResponse, DataResponse, DataContainerResponse> BuildAggregateFunc()
{
var result = Expression.Parameter(typeof(DataContainerResponse), "result");
var item = Expression.Parameter(typeof(DataResponse), "item");
var propertyTypes = new HashSet<Type> { typeof(decimal), typeof(int) };
var statements = item.Type.GetProperties()
.Where(p => propertyTypes.Contains(p.PropertyType))
.Select(p => Expression.AddAssign(
Expression.Property(result, p.Name),
Expression.Property(item, p)));
var body = Expression.Block(statements
.Concat(new Expression[] { result }));
var lambda = Expression.Lambda<Func<DataContainerResponse, DataResponse, DataContainerResponse>>(
body, result, item);
return lambda.Compile();
}
and the usage is simple:
public DataContainerResponse DoAggregation(List<DataResponse> source)
{
return source.Aggregate(new DataContainerResponse(), AggregateFunc);
}

Loop through object variables with different number on the name [duplicate]

This question already has answers here:
Variables in a loop
(9 answers)
Closed 2 years ago.
I have the following class:
public class Employees {
public string field1 { get; set; }
public string field2 { get; set; }
public string field3 { get; set; }
public string field4 { get; set; }
}
And i want to change values to all those members.
so i can to something like that:
Employees.field1 = "ghgf";
Employees.field2 = "ghgf";
Employees.field3 = "ghgf";
Employees.field4 = "ghgf";
but it's very ugly. and the amount of members will be 30, so this is not a good way...
I want to use for loop, that run over all the members and dynamic took the relevant field and change the value. for example:
for(int i=1; i<4; i++) {
var field = "field" + i;
Employees.field(the Var!!) = "fgdfd";
}
but in this line:
Employees.field(the Var!!) = "fgdfd";
I have a problem because field is the var that was defined in the for loop.
You can do it the hard (and not correct, IMO) way, using reflection.
But if you have 30 variable like this, change your approach: use a List<string>, or a Dictionary <whateverKey, string> to store all your fields
If you really must do it using reflection, you can do it like so:
var employees = new Employees();
var type = employees.GetType();
for (int i = 1; i <= 4; ++i)
type.GetProperty("field"+i).SetValue(employees, "abcde");
Console.WriteLine(employees.field1); // Prints "abcde"
As other folks have pointed out, using reflection in this way seems a little suspect. It looks like you should be doing it a different way, for example by using a Dictionary<string,string>.
You can do it using reflexion like that:
var myEmployees = new Employees();
var properties = myEmployees.GetType().GetProperties();
foreach (var field in properties)
{
field.SetValue(myEmployees, "NewValue");
}
// Print all field's values
foreach (var item in properties)
{
Console.WriteLine(item.GetValue(myEmployees));
}
Otherwise you can use a list or a dictionary or create a new struct that offre you more flexibility and let you able to control more properties of the field:
struct FieldProperties
{
public string Name { get; set; }
public string Value { get; set; }
public string Type { get; set; }
...
}
List<FieldProperties> lst = new List<FieldProperties>();
You can try using Reflection
Type type = typeof(Employees);
PropertyInfo pi = this.GetType().GetProperty();
pi.SetField(this, value);
Here is the MSDN link : https://msdn.microsoft.com/en-us/library/ms173183.aspx
Try this approach (using GetMembers()) to get all the members of a class and loop them.
Employees myEmployees = new Employees();
MemberInfo[] members = myType.GetMembers();
for (int i =0 ; i < members.Length ; i++)
{
// Display name and type of the concerned member.
Console.WriteLine( "'{0}' is a {1}", members[i].Name, members[i].MemberType);
}

Get fields from anonymous type

I have this class:
public class allFields
{
public string EAN { get; set; }
public string title { get; set; }
public string qty { get; set; }
public string price { get; set; }
public DateTime date { get; set; }
}
And a function that return an anonymous type:
public IEnumerable<object> stockEtatQty()
{
List<allFields> afList = new List<allFields>();
var query = from x in ctx.book
where x.qty > 0
select x;
foreach (var item in query)
{
allFields af = new allFields();
af.EAN = item.EAN;
af.title = item.Titre;
af.qty = ""+item.Quantite;
afList.Add(af);
}
var q = from x in afList
select new { EAN=x.EAN, Title=x.title, Quantity=x.qty };
return q; //q is a IEnumerable<'a> where a is new {string EAN, string Title, string Quantity}
}
In my WinForm a use this function as below:
private void QuantityToolStripMenuItem_Click(object sender, EventArgs e)
{
ServiceStock sstock = new ServiceStock();
var q = sstock.stockEtatQty().ToList();// q is a list<object>
string str = "";
foreach (var item in q)
{
str += item + Environment.NewLine;
}
MessageBox.Show(str);
}
The result is:
{ EAN = 1, Title = CSharp Security, Quantity = 970 }
{ EAN = 2, Title = MISC, Quantity = 100 }
...
What I want?
I want not like the result above, but separate each field apart of the item in the loop foreach, e.g get item.EAN, item.Title and item.Quantity.
If there is no solution for my problem I would like to know an alternative,
Thanks for help.
The obvious solution is to create a custom type (let's call it BookInfo) and return a IEnumerable<BookInfo> instead of a IEnumerable<object> (and maybe override ToString if you want to put the formatting into this class itself).
Then you can easily format the output.
public class BookInfo
{
public string EAN {get;set;}
public string Title {get;set;}
public int Quantity {get;set;}
}
public IEnumerable<BookInfo> stockEtatQty()
{
...
var q = from x in afList
select new BookInfo { EAN=x.EAN, Title=x.title, Quantity=x.qty };
return q;
}
private void QuantityToolStripMenuItem_Click(object sender, EventArgs e)
{
ServiceStock sstock = new ServiceStock();
var q = sstock.stockEtatQty();
var message = string.Join(Environment.NewLine,
q.Select(item => String.Format("{0} {1} {2}", item.EAN, item.Title, item.Quantity)));
MessageBox.Show(message);
}
Since the static type information about the object of anonymous type is lost by the time that you exit stockEtatQty() method, you could cast the object to dynamic and access fields like this:
str = string.Join(Environment.NewLine, q.Cast<dynamic>().Select(item =>
string.Format("{0} {1} {2}", item.EAN, item.Title, item.Quantity)
));
The cast to dynamic tells the compiler that EAN, Title, and Quantity need to be resolved at runtime.
Note that I also replaced the foreach loop with a call to string.Join to improve performance: repeated string concatenation creates unnecessary partial string objects, which string.Join avoids. Another solution would be to use StringBuider instead of string concatenation +=.
stockEtatQty is in a project (Service) and QuantityToolStripMenuItem_Click is in another project (View)
Unfortunately, this means that you would not be able to use anonymous types: anonymous types are generated with internal visibility, limiting their use to the assembly in which they are produced. You can use a work-around based on ExpandoObject described in this answer:
var q = afList.Select(x => {
dynamic res = new ExpandoObject();
res.EAN=x.EAN;
res.Title=x.title;
res.Quantity=x.qty;
return res;
});
Create a new class that represents the new object structure and return that.
var q = from x in afList
select new SmallerType { EAN=x.EAN, Title=x.title, Quantity=x.qty };
WinForm Function
foreach (SmallerType item in q)
{
//
}
You can use collection of dynamic objects instead of simple objects as return type of your method:
public IEnumerable<dynamic> stockEtatQty()
Then you will not have IntelliSense but at runtime properties will be found:
foreach (var item in sstock.stockEtatQty())
str += String.Format("{0}", item.EAN) + Environment.NewLine;
But I suggest you to create custom class with EAN, Title and Quantity properties. Or just use your allFields instead of anonymous objects.
Consider also to use StringBuilder for string creation to avoid creating lot of in-memory strings:
var builder = new StringBuilder();
foreach (var item in sstock.stockEtatQty())
builder.AppendFormat("{0}{1}", item.EAN, Environment.NewLine);
MessageBox.Show(builder.ToString());

For loop to add image to imagelist

I'm cleaning up my code trying to short in some things
Now I've stumbled across:
ImageList.Add(test.Properties.Resources.test1);
ImageList.Add(test.Properties.Resources.test2);
ImageList.Add(test.Properties.Resources.test3);
ImageList.Add(test.Properties.Resources.test4);
ImageList.Add(test.Properties.Resources.test5);
(There are 15 of these)
Was wondering if this could be shortened with a for loop
Something like:
for(int i=1; i<=15; i++)
ImageList.Add(test.Properties.Resources.test +i);
Now ofcourse this won't work but I have no clue how to do this (if even possible)
You can iterate over resources via this code
using System.Collections;
using System.Globalization;
using System.Resources;
...
ResourceSet resourceSet = MyResourceClass.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
foreach (DictionaryEntry entry in resourceSet)
{
string resourceKey = entry.Key;
object resource = entry.Value;
}
You can use reflection, to get the values:
public class Something
{
public int Test1 { get; set; }
public int Test2 { get; set; }
public int Test3 { get; set; }
public int Test4 { get; set; }
}
var thing = new Something();
var imageProperties = typeof(Something)
.GetProperties()
.Where(p => p.Name.StartsWith("Test"));
var imagesToAdd = imageProperties
.Select(property => property.GetValue(thing))
.ToList();
You could define a property of type IEnumerable<Image> in the class of Resources object
public IEnumerable<Image> Images
{
get
{
yield return test1;
yield return test2;
yield return test3;
yield return test4;
yield return test5;
...
}
}
and then use it to fill ImageList
foreach(var image in test.Properties.Resources.Images)
{
ImageList.Add(image);
}
I just found out that there is a library for evaluating C# expression called Flee. Apparently you can use it to evaluate C# code so that you can loop over variable names, just like JavaScript, but the need for it most likely means a design flaw.
http://flee.codeplex.com/

Categories

Resources