Add to List Property using the properties Index C# - c#

I want to user a foreach loop to add to a c# list without using the list properties Key name.
I have a list such as
public class Bus
{
public string Val1 { get; set; }
public string Val2 { get; set; }
public string Val3 { get; set; }
public string Val4 { get; set; }
public string Val5 { get; set; }
public string Val6 { get; set; }
// ...
public string Val127 { get; set; }
}
The lists I want to populate can have over 200 properties so I am trying to find a quick way to populate them without writing out the properties.
I want to populate this from a one dimensional array (line) using something like this
j = 0
for (int i = 0; i < lines.Length; i++)
{
foreach(Bus BusProp in BusList)
{
BusProp[j] = line[i+j];
j =+ 1;
}
}
This is not working. Any suggestions are appreciated

If you can't change the class definition, your main alternative option is to use reflection.
void Main()
{
var bus = new Bus();
var data = new string[6] { "A", "B", "C", "D", "E", "F" };
for (var i = 1; i <= 6; i++)
{
bus.GetType().GetProperty("Val" + i.ToString()).SetValue(bus, data[i - 1]);
}
Console.WriteLine(bus.Val5); // E
}
public class Bus
{
public string Val1 {get;set;}
public string Val2 {get;set;}
public string Val3 {get;set;}
public string Val4 {get;set;}
public string Val5 {get;set;}
public string Val6 {get;set;}
}
Needless to say, this is quite expensive, and may be hard to maintain. Make sure you don't have a more reasonable option (e.g. changing the class to contain arrays instead of indexed properties, using code generation...) before using this.
Even if your database has some COBOL-like monstrosity with 150 indexed columns, there shouldn't be a reason why your application can't deal with them in the form of Item[34] instead of Item34 - isolate the application code from the fixed constraints you're not happy with.

Why not use
public class Bus
{
public string[] Val = new string[127];
}
j = 0;
for (int i = 0; i<lines.Length; i++)
{
foreach(Bus BusProp in BusList)
{
BusProp.Val[j] = line[i + j];
j =+ 1;
}
}

Try this
var typ = typeof(Bus);
var prop = typ.GetProperty($"Val{j}");

I feel like the answers so far haven't satisfied your needs, thus here's my solution:
static void Main(string[] args)
{
//Create a string array containing the desired property names, in this case I'll use a loop
List<string> DesiredProperties = new List<string>();
for (int i = 0; i < 100; i++)
{
DesiredProperties.Add(string.Format("Property{0}", i));
}
//Call the method that returns the object and pass the array as parameter
var Bus = CreateDynamicObject(DesiredProperties);
//Display one of the properties
Console.WriteLine(Bus.Property99);
Console.Read();
}
private static dynamic CreateDynamicObject(List<string> PropertyList)
{
dynamic obj = new System.Dynamic.ExpandoObject();
foreach (string Prop in PropertyList)
{
//You can add the properties using a dictionary. You can also give them an initial value
var dict = (IDictionary<string, object>)obj;
dict.Add(Prop, string.Format("The value of {0}", Prop));
}
return obj;
}
This piece of code will add 100 properties to var "Bus", which can be accessed and applied a value at will.

Related

Pass a different list types to method and loop through it like array

// i have this class
public class SCHOOL
{
public int ID { get; set; }
public string Name { get; set; }
public string Country{ get; set; }
public decimal Total{ get; set; }
}
// and another class with different type
public class CLASS_2
{
public string Student { get; set; }
public DateTime Graduate { get; set; }
}
// and may bee i add class 3 and 4 with different type
// i fill the lists with my data
static void Main()
{
List < SCHOOL> FirstClass = new List < SCHOOL>();
FirstClass.Add( new SCHOOL{ID=1,Name="aaa",County="USA",Total=10});
FirstClass.Add( new SCHOOL{ID=1,Name="bbb",County="JAP",Total=7});
FirstClass.Add( new SCHOOL{ID=1,Name="ccc",County="GBR",Total=5});
List < CLASS_2 > SecondClass = new List < CLASS_2 >();
SecondClass.Add( new CLASS_2 {Student =1, Graduate ="2/6/2015"});
SecondClass.Add( new CLASS_2 {Student =1, Graduate ="2/4/2015"});
SecondClass.Add( new CLASS_2 {Student =1, Graduate ="2/8/2015"});
}
// i want to pass the first List and loop through my data
GetmyData ( firstClass);
// and also pass another List with different Class type to the same method and also loop through my data
GetmyData ( SenecdClass );
// i want one method to get the list and loop throught the data like array
private void GetmyData <T> ( List<T> newlist )
{
for (int y=0; y < newList.Count; y++)
{
for ( int x=0 ; x < newLsit[y].Colms; x++ )
{
Console.WriteLine ( newList[y][x].value );
}
}
}
I would say that firstly you need to use a generic method:
private void GetMyData(List<T> the List)
{
foreach (T entry in theList)
{
//deal with the entry on the list
}
}
and for the printing every property of the class, the best way in my eyes would be to override ToString
but if you need to access each property for something other than just displaying it will require reflection:
private void GetMyData(List<T> the List)
{
foreach (T entry in theList)
{
foreach (var property in typeof(T).GetProperties())
{
var propertyName = property.Name;
var propertyValue = property.GetValue(entry);
Console.WriteLine("Value of " + propertyName + " is " + propertyValue);
}
}
}
but bear in mind that not all properties can be read.
static void GetMyData(List theList)
{
int count = typeof(T).GetProperties().Count();
for ( int y = 0 ; y < theList.Count ; y++ )
{
for ( int x = 0; x < count; x++ )
{
var propertyName = typeof(T).GetProperties()[x].Name;
var propertyValue = typeof(T).GetProperties()[x].GetValue( theList[y] , null );
var propertyType = typeof(T).GetProperties()[x].PropertyType;
Console.WriteLine(propertyType + " " + propertyName + " " + propertyValue );
}
}
}

C# Developing .Net3.5 using reflection to get/set values to nested properties and/or nested fields

I'm developing an app that works with data block classes inheritied from a base class and I am trying to use Reflection to drill down to properties/fields in my data block class. Since all the data block classes are derived/inherited from the base class (which contains a Size property) I can use a general variable of type base class to create an object in my app easily enough; I can also get/set properties at a top level. My problem occurs when the property is a field - I do not know how to get to the next level in the field to get to the base properties and/or fields, if applicable.
My BaseClass:
namespace MyBase {
public class BaseClass {
private int _size;
public BaseClass() { }
public BaseClass(int size) {
_size = size;
}
public int Size() {
return _size;
}
}
}
Data block class #1:
namespace DataBlock_class {
//Data block class #1: (contains simple properties - will be used later)
public class RecordBlock1_class : MyBase.BaseClass {
public byte Char { get; set; }
public byte Color { get; set; }
public RecordBlock1_class() : base(2) {
Char = 0;
Color = 0;
}
}
//Data block class #2: (contains simple properties)
public RecordBlock2_class : MyBase.BaseClass {
public bool Boolean1 { get; set; }
public byte Byte1 { get; set; }
public short Short1 { get; set; }
public ushort UShort1 { get; set; }
public RecordBlock2_class() : base(11) {
Boolean1 = false;
Byte1 = 0;
Short1 = 0;
UShort1 = 0;
}
}
//Data block class #3: (contains simple properties & fields)
public RecordBlock3_class : MyBase.BaseClass {
public int Int1 { get; set; }
public uint UInt1 { get; set; }
public RecordBlock1_class[] ArrayField1 { get; set; } // array of 12
public RecordBlock1_class[] ArrayField2 { get; set; } // array of 12
public RecordBlock1_class[] ArrayField3 { get; set; } // array of 12
public RecordBlock2_class() : base(34) {
Int1 = 0;
UInt1 = 0;
ArrayField1 = new RecordBlock1_class[12];
for(int x = 0; x < 12; x++) {
ArrayField1[x] = new RecordBlock1_class();
}
ArrayField2 = new RecordBlock1_class[12];
for(int x = 0; x < 12; x++) {
ArrayField2[x] = new RecordBlock1_class();
}
ArrayField3 = new RecordBlock1_class[12];
for(int x = 0; x < 12; x++) {
ArrayField3[x] = new RecordBlock1_class();
}
}
}
}
Since all my data block classes derive/inherit from MyBase.BaseClass, I can use this for my variable - I do not what type of data block class I will be processing at run time.
in my C# app, I have the following block of code:
string CSharpQualifiedName = "<this could be any of the data block classes above>";
// DataBlock_class.RecordBlock1_class
// DataBlock_class.RecordBlock2_class
// DataBlock_class.RecordBlock3_class
Using my MyBase.BaseClass variable, I can then instantiate a MyBase.BaseClass object:
MyBase.BaseClass baseClass = null;
Type baseClassType = Type.GetType(CSharpQualifiedName);
if(baseClassType == null) {
foreach(Assembly asm in AppDomain.CurrentDomain.GetAsseblies()) {
baseClassType= asm.GetType(CSharpQualifiedName);
if(baseClassType != null) {
baseClass = Activator.CreateInstance(baseClassType) as MyBase.BaseClass;
break;
}
}
}
Dealing with the first two data block classes are easy enough - I can using PropertyInfo to get/set values.
string fieldProperty = "<any property in the class>";
PropertyInfo pi = baseClass.GetType().GetProperty(fieldProperty);
Now, my proplem/issue is RecordBlock3_class - How do I get to one of the items in any of array fields/properties AND then to the Char/Color property in RecordBlock1_class???
I can use FieldInto to get to the ArrayFieldX fields, but I'm lost after that?
FieldInfo fi = baseClass.GetType().GetField(fieldProperty);
Any assistance/advice is greatly appreicated!! I will say one more thing, the data block classes can get a bit more complex as users create more nested class structures.
You can get element type of the array property by Reflection also, and then get its properties normally:
string fieldProperty = "ArrayField1";
System.Reflection.PropertyInfo pi = baseClass.GetType().GetProperty(fieldProperty);
if (pi.PropertyType.IsArray)
{
Type elementType = pi.PropertyType.GetElementType();
System.Reflection.PropertyInfo pi2 = elementType.GetProperty("Color");
}
Based on that, you can write simple yet more generic function that is traversing nested properties (to use also fields, simply modify below code):
static System.Reflection.PropertyInfo GetProperty(Type type, string propertyPath)
{
System.Reflection.PropertyInfo result = null;
string[] pathSteps = propertyPath.Split('/');
Type currentType = type;
for (int i = 0; i < pathSteps.Length; ++i)
{
string currentPathStep = pathSteps[i];
result = currentType.GetProperty(currentPathStep);
if (result.PropertyType.IsArray)
{
currentType = result.PropertyType.GetElementType();
}
else
{
currentType = result.PropertyType;
}
}
return result;
}
and then you can 'query' objects with 'paths':
PropertyInfo pi = GetProperty(c1.GetType(), "ArrayField1/Char");
PropertyInfo pi2 = GetProperty(c2.GetType(), "Color");
If you want to get values of object in this way, a method will be similar:
static object GetPropertyValue(object obj, string propertyPath)
{
System.Reflection.PropertyInfo result = null;
string[] pathSteps = propertyPath.Split('/');
object currentObj = obj;
for (int i = 0; i < pathSteps.Length; ++i)
{
Type currentType = currentObj.GetType();
string currentPathStep = pathSteps[i];
var currentPathStepMatches = Regex.Match(currentPathStep, #"(\w+)(?:\[(\d+)\])?");
result = currentType.GetProperty(currentPathStepMatches.Groups[1].Value);
if (result.PropertyType.IsArray)
{
int index = int.Parse(currentPathStepMatches.Groups[2].Value);
currentObj = (result.GetValue(currentObj) as Array).GetValue(index);
}
else
{
currentObj = result.GetValue(currentObj);
}
}
return currentObj;
}
And then you can get values queries, including arrays, for example:
var v = GetPropertyValue(baseClass, "ArrayField1[5]/Char");
Of course both methods requires some polishing of error handling etc.

Using C# Reflection to assign collection of variable size to class properties

I have a destination class called Foo with the following properties:
public string Bar1 { get; set; }
public string Bar2 { get; set; }
public string Bar3 { get; set; }
public string Bar4 { get; set; }
public string Bar5 { get; set; }
public string Bar6 { get; set; }
I'm reading in a file that could have any number of "Bars" which I read into a collection called fileBars. I need to find out how to use Reflection to iterate over fileBars and assign the first one to Bar1, the second one to Bar2, etc.
I've tried several things I've found online, most recently playing with what's shown below, but I haven't had any luck. Can someone who is familiar with Reflection point me in the right direction?
var count = fileBars.Count();
var myType = Foo.GetType();
PropertyInfo[] barProperties = null;
for (var i = 0; i < count; i++)
{
barProperties[i] = myType.GetProperty("Bar" + i + 1);
}
I don't think you need to store the PropertyInfo objects in an array; you can just assign the values as you go:
var count = fileBars.Count();
var instance = new Foo();
for (var i = 1; i <= count; i++)
{
var property = typeof(Foo).GetProperty("Bar" + i);
if(property != null)
property.SetValue(instance, fileBars[i - 1];
else
// handle having too many bars to fit in Foo
}
You need to initialize barProperties:
PropertyInfo[] barProperties = new PropertyInfo[count];
To assign a value to the property, use SetValue:
barProperties[i].SetValue(Foo, fileBars[i] );
Unless you need to keep all the properties you find for later, you don't need the barProperties array:
var myType = foo.GetType();
int barCount = 0;
foreach(string barValue in fileBars)
{
barCount++;
var barProperty = myType.GetProperty("Bar" + barCount);
barProperty.SetValue(foo, barValue, null);
}

Combining numbers and names collections

I have 2 List collections. One contains numbers, the other names. There are twice as many numbers as names(always). I want to take the first name from the collection and the first two numbers from the other collection then put them together in a 3rd user collection of (VentriloUser). Then the second name needs to be matched with the 3rd and 4th numbers and so on.
I was thinking something with a for or foreach loop, but I can't wrap my head around it right now.
public class VentriloUser
{
public VentriloUser(string name, int seconds, int ping)
{
Name = name; Seconds = seconds; Ping = ping;
}
public string Name { get; set; }
public int Ping { get; set; }
public int Seconds { get; set; }
}
public class Ventrilo
{
public Ventrilo(string statusurl)
{
StatusURL = statusurl;
}
public string StatusURL { get; set; }
public string HTML { get; set; }
public List<VentriloUser> Users { get; set; }
private Regex findNumbers = new Regex("\\<td width=\"10%\" bgcolor=\"#\\w{6}\"\\>\\<font color=\"#000000\">\\<div style=\"overflow:hidden;text-overflow:ellipsis\"\\>-?\\d+\\<");
private Regex findNames = new Regex("\\<td width=\"20%\" bgcolor=\"#\\w{6}\"\\>\\<font color=\"#000000\">\\<div style=\"overflow:hidden;text-overflow:ellipsis\"\\>\\b\\w+\\<");
private WebClient wClient = new WebClient();
public void DownloadHTML()
{
HTML = wClient.DownloadString(StatusURL);
}
public List<int> GetNumbers()
{
var rawnumbers = findNumbers.Matches(HTML);
var numbers = new List<int>();
foreach (var rawnumber in rawnumbers)
{
var match = Regex.Match(rawnumber.ToString(), "\\>\\-?\\d+\\<");
string number = Regex.Replace(match.ToString(), "\\<|\\>", "");
numbers.Add(Convert.ToInt32(number));
}
return numbers;
}
public List<string> GetNames()
{
var rawnames = findNames.Matches(HTML);
var names = new List<string>();
foreach (var rawname in rawnames)
{
var match = Regex.Match(rawname.ToString(), "\\>\\w+<");
string name = Regex.Replace(match.ToString(), "\\<|\\>", "");
names.Add(name);
}
return names;
}
public List<VentriloUser> GenerateUsers()
{
var numbers = GetNumbers();
var names = GetNames();
var users = new List<VentriloUser>();
}
}
I am a hobbyist, but hope to pursue a career one day. Any help is much appreciated. Thank you for your time.
Using LINQ:
var users = names.Select((name,idx) => new VentriloUser(name, numbers[idx*2], numbers[idx*2+1]))
.ToList();
Using loops:
var users = new List<VentriloUser>();
for (int i = 0; i < names.Count; i++)
{
var name = names[i];
int j = i * 2;
if (j >= numbers.Count - 1)
break; // to be safe...
users.Add(new VentriloUser(name, numbers[j], numbers[j + 1]));
}

C# Trouble adding to a generic list

This is a follow up question from another post but that post was answered. I have a for loop that I want to add three items to a generic class and I'm not sure how to do that. How do I add those items?
private static void TestResults()
{
List<Record> Records = new List<Record>();
for (int i = 0; i < ProxyList.Count; i++)
{
string[] split = List[i].Split('|');
// This is what i dont know how to do
// split[0] = Name, split[1] = SomeValue and split[3] = OrderNr
}
}
class Records
{
public static string Name { get; set; }
public static int SomeValue { get; set; }
public static int OrderNr { get; set; }
}
The first step is to associate the fields with instances of Records vs. the type itself. This is done by removing the static modifier
class Records
{
public string Name { get; set; }
public int SomeValue { get; set; }
public int OrderNr { get; set; }
}
To actually create instances try the following
for (int i = 0; i < ProxyList.Count; i++) {
string[] split = List[i].Split('|');
Records record = new Records() {
Name = split[0]
SomeValue = Int32.Parse(split[1])
OrderNr = Int32.Parse(split[2])
};
Records.add(record);
}
This particular example uses an object initializer to combine the acts of creating the object and settings its fields. This could be expanded into the longer form as follows
for (int i = 0; i < ProxyList.Count; i++) {
string[] split = List[i].Split('|');
Records record = new Records();
record.Name = split[0];
record.SomeValue = Int32.Parse(split[1]);
record.OrderNr = Int32.Parse(split[2]);
Records.add(record);
}
The Int32.Parse method will throw an exception if the item in the original string wasn't a number. If this is a possibility (think bad input) then you'll want to wrap the creation of Records with a try / catch statement
Well for one thing, your properties must not be static. You want different data for each instance, right? So they need to be instance properties. Personally I'd also make the type immutable, but that's another matter:
class Record // Changed from Records; each object is only a single record...
{
public string Name { get; set; }
public int SomeValue { get; set; }
public int OrderNumber { get; set; }
}
private static List<Record> ConvertRecords(IEnumerable<string> lines)
{
List<Record> records = new List<Record>();
foreach (string line in lines)
{
string[] split = line.Split('|');
Record record = new Record {
Name = split[0],
SomeValue = int.Parse(split[1]),
OrderNumber = int.Parse(split[2]);
};
records.Add(record);
}
}
As of C# 3 / .NET 3.5, a more idiomatic approach would be to use LINQ:
private static List<Record> ConvertRecords(IEnumerable<string> lines)
{
return (from line in lines
let split = line.Split('|')
select new Record {
Name = split[0],
SomeValue = int.Parse(split[1]),
OrderNumber = int.Parse(split[2]);
}).ToList();
}
}
... on the other hand, that's relatively advanced if you're really just starting to learn the language.
To be honest, Stack Overflow is better for asking specific questions than structured learning - I suggest you get hold of a good book, such as C# 4 in a Nutshell.
I'm not sure why you use static !!! but try this :
private static void TestResults()
{
List<Record> Records = new List<Record>();
for (int i = 0; i < ProxyList.Count; i++)
{;
string[] split = List[i].Split('|');
Records.Add(new Record() {Name = Namesplit[0] , SomeValue = split[1], OrderNr = split[3]}) ;
}
}

Categories