Reputation: 9017
I have a pretty simple piece of code:
var list = new List<MyType>();
list = MyItems.Where(x => x.Name.ToLower().Contains(e.Text.ToLower())).ToList();
for (int i = itemOffset; i < endOffset; i++)
{
combo.Items.Add(new ComboItem(list[i].Name, list[i].Id.ToString()));
}
What I want to do is to make this a generic function that accepts list of any type and accepts two strings as properties. (In this case two properties that we are looking at are Name and Id.
private void MakeCombo<T>(Combo combo, IEnumerable<T> lst, string Field1, string Field2)
{
var list = list = lst.Where(x => x.Field1.ToLower().Contains(searchText.ToLower())).ToList(); //How make this to work???
for (int i = itemOffset; i < endOffset; i++)
{
combo.Items.Add(new ComboItem(list[i].Field1, list[i].Field2.ToString())); //How make this to work???
}
}
Now, I do not understand how can I access properties of generic list by string names (Field1 and Field2).
Upvotes: 3
Views: 9117
Reputation: 1725
You will have to use reflection:
typeof(x).GetField("Field1", BindingFlags.Public).GetValue()
You could do that for both objects and compare the values.
Upvotes: 2
Reputation: 203821
One way of solving this problem, if you don't have the ability of creating an interface and ensuring all of the items in the sequence implement that interface (as shown in this other answer), is to use delegates. By passing in two functions, each of which take a T
as input, and return a string
or object
as the output, you can mimic that functionality:
private void MakeCombo<T>(Combo combo, IEnumerable<T> sequence
, Func<T, string> field1Selector, Func<T, object> field2Selector)
{
var foundItems = sequence.Where(item => field1Selector(item).ToLower()
.Contains(searchText.ToLower()));
foreach(var item in foundItems)
{
combo.Items.Add(new ComboItem(field1Selector(item), field2Selector(item).ToString()));
}
}
From the calling side it might look something like this (to use your first code snippet as an example:
MakeCombo(combo, list, item => item.Name, item => item.Id);
Upvotes: 5
Reputation: 23675
private void MakeCombo<T>(Combo combo, IEnumerable<T> list)
{
Type type = typeof(T);
List<T> comboList = list.Where(x => ((String)type.GetField("Field1", (BindingFlags.Public | BindingFlags.Instance)).GetValue(x)).ToLower().Contains(m_SearchText.ToLower()));
for (Int32 i = m_ItemOffset; i < m_OffsetEnd; ++i)
combo.Items.Add(new ComboItem((String)type.GetField("Field1", (BindingFlags.Public | BindingFlags.Instance)).GetValue(list[i]), (String)type.GetField("Field2", (BindingFlags.Public | BindingFlags.Instance)).GetValue(list[i])));
}
Upvotes: 1
Reputation: 18534
If you could define an interface, describing all the fields available, and make each type, that is suitable for this method implement that interface, it would look like this (and would be IMO better, than accessing fields by names):
public interface IFields
{
string Prop1 { get; set; }
string Prop2 { get; set; }
}
public static void DoSmth<T>(List<T> items) where T : IFields
{
foreach (T t in items)
{
Console.WriteLine(t.Prop1);
Console.WriteLine(t.Prop2);
}
}
Upvotes: 1