Reputation: 63
I have a class that contains a couple of lists of different class types which all of them has a Percent
property; I want to get one of these lists dynamically through it's name (i.e., I want to pass the name of the list to the GetPropery
method to get the list) and then iterate over the list's entries. The problem is when I use the GetPropery
method this will get an object
and does not recognize that it is a List; so I cannot loop over it.
the class that I want to use it's properties:
public class ModelOfExcel_VM : Object
{
public ModelOfExcel_VM()
{
}
public List<Sheet_1_VM> Sheet1 { get; set; }
public List<Sheet_2_VM> Sheet2 { get; set; }
public List<Sheet_3_VM> Sheet3 { get; set; }
public List<Sheet_4_VM> Sheet4 { get; set; }
public List<Sheet_5_VM> Sheet5 { get; set; }
public List<Sheet_6_VM> Sheet6 { get; set; }
public List<Sheet_7_VM> Sheet7 { get; set; }
public List<Sheet_8_VM> Sheet8 { get; set; }
public List<Sheet_9_VM> Sheet9 { get; set; }
}
Here is the sample code:
private void PercentValidation()
{
ModelOfExcel_VM excel = new ModelOfExcel_VM;
var pageswithpercent = new List<string>() { "3", "5", "7", "8", "9"};
foreach (var page in pageswithpercent)
{
var thisPage = excel.GetType().GetProperty("Sheet" + page).GetValue(excel, null);
//this loop will lead to an error due thisPage has type of object and is not iteratable.
foreach (var item in thisPage)
{
Console.WriteLine(item.Percent);
}
}
}
I also have used interfaces but it does not work either because when I use the Type of interface instead of the class Type in the foreach loop I can not use the Percent
property because it refers to Percent property in IPercent
interface rather than Percent property in the original class of the object(each list has a different class type but also has implemented the IPercent
interface). If I use var
it will refer to object
type and then as you know I cannot access properties in the class.
the interface approach:
interface IPercent
{
float Percent{ get; set; }
}
private void PercentValidation()
{
ModelOfExcel_VM excel = new ModelOfExcel_VM;
var pageswithpercent = new List<string>() { "3", "5", "7", "8", "9"};
foreach (var page in pageswithpercent)
{
var thisPageObject = excel.GetType().GetProperty("Sheet" + page).GetValue(excel, null);
var thisPage = (IEnumerable<IPercent>)thisPageObject;
//bellow if I use var instead of IPercent as the type of item it would be recognized as object.
foreach (IPercent item in thisPage)
{
//here the percent property refers to interface itself
Console.WriteLine(item.Percent);
}
}
}
it is straightforward in java script but How can I do this in c#?
Upvotes: 1
Views: 346
Reputation: 42350
There are some things about your question which don't make sense:
Sheet1
, Sheet2
, etc, but you're trying to access properties called Sheet_1_VM
, Sheet_2_VM
, etc, using reflectionthisPageObject
to List<IPercent>
, but this is not possibleitem.Percent
has type float
, and cannot refer to an interfaceHowever, we can gloss over these issues, and skip to the core question: given an object which might be a List<Sheet_1_VM>
or a List<Sheet_2_VM>
, where both Sheet_1_VM
and Sheet_2_VM
implement IPercent
, how can we iterate over each element in the list.
The reason you can't cast a List<Sheet_1_VM>
to a List<IPercent>
is because List<T>
is not covariant. A List<Sheet_1_VM>
is a list which contains only Sheet_1_VM
objects (or their subclasses): you wouldn't be able to put a Sheet_2_VM
into a List<Sheet_1_VM>
. However, if you pretended that your List<Sheet_1_VM>
was a List<IPercent>
, then you would be able to put any object which implemented IPercent
into it (by calling List<T>.Add
). That means you would be able to put a Sheet_2_VM
into your List<Sheet_1_VM>
, which obviously makes no sense!
However, List<T>
implements IEnumerable<T>
, and IEnumerable<T>
is covariant. This means that it only lets you take items out of the collection, and doesn't let you put them in (there's no Add
method). Therefore it is safe to treat a List<Sheet_1_VM>
as an IEnumerable<IPercent>
, because there's no danger of anyone putting a Sheet_2_VM
in.
This lets us write this:
public interface IPercent
{
float Percent { get; }
}
public class Sheet_1_VM : IPercent
{
public float Percent { get; set; }
}
public class Sheet_2_VM : IPercent
{
public float Percent { get; set; }
}
public class ModelOfExcel_VM : Object
{
public List<Sheet_1_VM> Sheet1 { get; set; }
public List<Sheet_2_VM> Sheet2 { get; set; }
}
public static class Program
{
public static void Main()
{
var model = new ModelOfExcel_VM()
{
Sheet1 = new List<Sheet_1_VM>()
{
new Sheet_1_VM() { Percent = 1.0f },
new Sheet_1_VM() { Percent = 2.0f },
},
Sheet2 = new List<Sheet_2_VM>()
{
new Sheet_2_VM() { Percent = 3.0f },
new Sheet_2_VM() { Percent = 4.0f },
},
};
var pageswithpercent = new List<string>() { "1", "2" };
foreach (var page in pageswithpercent)
{
var thisPage = (IEnumerable<IPercent>)model.GetType().GetProperty("Sheet" + page).GetValue(model);
foreach (var item in thisPage)
{
Console.WriteLine(item.Percent);
}
}
}
}
Upvotes: 3