C
C#ā€¢14mo ago
Nurglini

Is there a 'foreach' equivalent for parts of a class?

I have a class (Stored) defined that has strings stored (Name, ID, and Data, then some others I havent settled on a name for). Many of these are going to be integers stored as strings and would like to be able to go down each element whenever a Stored object is inputted and format them in a certain way if they are actually a number. I'm not familiar with how foreach works but from what I've read it can't be used for classes - is there an equivalent I can use to accomplish this?
29 Replies
Thinker
Thinkerā€¢14mo ago
So to be clear, you have a class with several string properties and you want to iterate over those properties?
Nurglini
NurgliniOPā€¢14mo ago
Yes, rather than manually changing them one at a time (having to repeat an if statement each time), I essentially just write it the once.
ZacharyPatten
ZacharyPattenā€¢14mo ago
What you are asking for is "dynamic" code. In general you want to avoid dynamic code. There is almost always a better design thatn using dynamic code. There are many reasons for this, but I'll just leave it at that unless you want more info. Having said that, if you hate you life and still want to use dynamic code... one option is to use reflection
using System;

var properties = typeof(MyClass).GetProperties();

foreach (var property in properties)
{
Console.WriteLine($"{property.Name} {property.PropertyType}");
}

public class MyClass
{
public int A { get; set; }
public double B { get; set; }
public string C { get; set; }
}
using System;

var properties = typeof(MyClass).GetProperties();

foreach (var property in properties)
{
Console.WriteLine($"{property.Name} {property.PropertyType}");
}

public class MyClass
{
public int A { get; set; }
public double B { get; set; }
public string C { get; set; }
}
output:
A System.Int32
B System.Double
C System.String
A System.Int32
B System.Double
C System.String
there is an example, but again... you shouldn't use reflection general another option is to make a source generator
Thinker
Thinkerā€¢14mo ago
It is way easier to just bite the bullet and write a method to do whatever you want to each property individually. Action<string> might be of use if you want to apply the same operation to all the properties.
ZacharyPatten
ZacharyPattenā€¢14mo ago
but that is rather complex and I would not recommend source generators for beginners if your code is verbose, then you can likely clean it up. can you share your current code and we might be able to help you?
Angius
Angiusā€¢14mo ago
>integers stored as strings šŸ’€ Let me guess, JS background?
Nurglini
NurgliniOPā€¢14mo ago
I'm afraid I don't understand how it would be damning? My efforts at the moment are basically equivalent to going through and doing a .ToUpper() for each one if it's a certain length
Thinker
Thinkerā€¢14mo ago
class MyClass
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }

public UpdateAll(Func<string, string> action)
{
A = action(A);
B = action(B);
C = action(C);
}
}
class MyClass
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }

public UpdateAll(Func<string, string> action)
{
A = action(A);
B = action(B);
C = action(C);
}
}
myClass.Update(s =>
{
if (s.Length > 3) return s.ToUpper();
return s;
});
myClass.Update(s =>
{
if (s.Length > 3) return s.ToUpper();
return s;
});
ZacharyPatten
ZacharyPattenā€¢14mo ago
as you get more experience you will understand why using dynamic code is bad but for now, can you share your current code? we can probably help you clean up your current code
Nurglini
NurgliniOPā€¢14mo ago
I'm away from my computer at the moment, I can later though For reference, how do I format my message to appear like this?
ZacharyPatten
ZacharyPattenā€¢14mo ago
$codegif
Nurglini
NurgliniOPā€¢14mo ago
int Counter;
string[] NameOptions = {"Jim", "Kim",..};
public class Stored
{
public string ID;
public string Name;
public string Turns;
public string Health;
public string Size;
public string Data;
}
List<Stored> AllItems = new List<Stored>();

void GenerateStored(int number)
{
if(Counter < 99)
{
for (int i = 0; i < number; i++;)
{
Stored temp = new Stored() {ID = Counter.ToString(), Name = Random.Range(0, NameOptions.Length).ToString(),.../*etc. for everything except 'Data'*/}
StoredDataSet(temp);

AllItems.Add(temp)

}
}
}

void StoredDataSet(Stored l)
{
Stored temp = l;
if(Convert.ToInt16(temp.ID) < 10)
{
temp.ID = '0' + temp.ID;
}
if(Convert.ToInt16(temp.Name) < 10)
{
temp.Name = '0' + temp.Name;
}
...
/*^This all is what I'd like to streamline formatting - storing a string as 01 rather than just 1 works better for what I'd like to do^*/
temp.Data = temp.ID + temp.Name + temp.Turns.../*Through to Size*/;
}
int Counter;
string[] NameOptions = {"Jim", "Kim",..};
public class Stored
{
public string ID;
public string Name;
public string Turns;
public string Health;
public string Size;
public string Data;
}
List<Stored> AllItems = new List<Stored>();

void GenerateStored(int number)
{
if(Counter < 99)
{
for (int i = 0; i < number; i++;)
{
Stored temp = new Stored() {ID = Counter.ToString(), Name = Random.Range(0, NameOptions.Length).ToString(),.../*etc. for everything except 'Data'*/}
StoredDataSet(temp);

AllItems.Add(temp)

}
}
}

void StoredDataSet(Stored l)
{
Stored temp = l;
if(Convert.ToInt16(temp.ID) < 10)
{
temp.ID = '0' + temp.ID;
}
if(Convert.ToInt16(temp.Name) < 10)
{
temp.Name = '0' + temp.Name;
}
...
/*^This all is what I'd like to streamline formatting - storing a string as 01 rather than just 1 works better for what I'd like to do^*/
temp.Data = temp.ID + temp.Name + temp.Turns.../*Through to Size*/;
}
I am aware that a foreach style system would need to be sure to not edit Data as its a part of the class
Pobiega
Pobiegaā€¢14mo ago
perhaps you should just embrace the type system more? šŸ™‚
MODiX
MODiXā€¢14mo ago
Pobiega
REPL Result: Success
var stored = new Stored { Id = 5, Name = 500 };

Console.WriteLine($"Id: {stored.Id}");
Console.WriteLine($"Name: {stored.Name}");

public class Stored
{
public FormattedInt Name { get; set; }
public FormattedInt Id { get; set; }
}

public class FormattedInt
{
private FormattedInt(int value)
{
Value = value;
}

public int Value { get; set; }

public override string ToString() => Value.ToString("00");

public static implicit operator FormattedInt(int value) => new(value);
}
var stored = new Stored { Id = 5, Name = 500 };

Console.WriteLine($"Id: {stored.Id}");
Console.WriteLine($"Name: {stored.Name}");

public class Stored
{
public FormattedInt Name { get; set; }
public FormattedInt Id { get; set; }
}

public class FormattedInt
{
private FormattedInt(int value)
{
Value = value;
}

public int Value { get; set; }

public override string ToString() => Value.ToString("00");

public static implicit operator FormattedInt(int value) => new(value);
}
Console Output
Id: 05
Name: 500
Id: 05
Name: 500
Compile: 739.703ms | Execution: 104.325ms | React with āŒ to remove this embed.
Pobiega
Pobiegaā€¢14mo ago
would something like this work? could actually even be a struct
public struct FormattedInt
{
private FormattedInt(int value)
{
Value = value;
}

public int Value { get; set; }

public readonly override string ToString() => Value.ToString("00");

public static implicit operator FormattedInt(int value) => new(value);
}
public struct FormattedInt
{
private FormattedInt(int value)
{
Value = value;
}

public int Value { get; set; }

public readonly override string ToString() => Value.ToString("00");

public static implicit operator FormattedInt(int value) => new(value);
}
Angius
Angiusā€¢14mo ago
record struct to get rid of the ctor and property šŸ˜›
Pobiega
Pobiegaā€¢14mo ago
sick
public readonly record struct FormattedInt(int Value)
{
public override string ToString() => Value.ToString("00");

public static implicit operator FormattedInt(int value) => new(value);
}
public readonly record struct FormattedInt(int Value)
{
public override string ToString() => Value.ToString("00");

public static implicit operator FormattedInt(int value) => new(value);
}
sorry, my brain is full of snot atm šŸ˜„ @Goblini , have a look
Nurglini
NurgliniOPā€¢14mo ago
That's neat, but I would still have to go through each individual element, wouldnt I?
Anu6is
Anu6isā€¢14mo ago
what do you mean by go through each element?
Nurglini
NurgliniOPā€¢14mo ago
The items ID, Name, Turns, etc.
Anu6is
Anu6isā€¢14mo ago
yes, those are the properties but what is your usecase for iterating through them simply doing ID.ToString(), Name.ToString() etc would give you what you want
Nurglini
NurgliniOPā€¢14mo ago
Yes but I would need to enter that manually for each property, I'm asking if there's a way to input a class and perform the function for each property, regardless of how many there are or what their names are.
Anu6is
Anu6isā€¢14mo ago
then you are back to reflection ^
Nurglini
NurgliniOPā€¢14mo ago
Ah, so there isn't a more efficient way than doing it manually
Anu6is
Anu6isā€¢14mo ago
needs tweaking for what you want but that's the general idea nope
Nurglini
NurgliniOPā€¢14mo ago
Thanks
Anu6is
Anu6isā€¢14mo ago
if you want to access some random amount of properties without knowing their names, definitely reflection
Angius
Angiusā€¢14mo ago
Alternatively, use a source generator so you don' pay the performance price of using reflections
Want results from more Discord servers?
Add your server