I have a List<T> variable where T is not known at compile time. I need to access the value property on type T like this
foreach(var item in items) // items is List<T>
{
item.value // this won't compile because T is unknown
}
I know that <T> in my case will have the value property. How can I access it?
If you KNOW that every T has VALUE you can use dynamic instead of var
foreach(dynamic item in items) //items is List<T>
{
item.VALUE
}
As already answered the correct way is to create an interface that implements the Value prop.
However you have commented that you have no control over classes you will need to do this another way.
One way would be reflection, I'm assuming your property name is VALUE, (case sensitive)
PropertyInfo pi = typeof(T).GetProperty("VALUE");
object value = pi == null ? null pi.GetValue(item,null);
You could cache the reflection call into a static generic class that creates a static field the first time it is used.
Alternatively you could use a static generic helper class with field and a helper method.
public static class ValueHelper<T> {
public static Func<T,object> ValueFunction;
public static object GetValue(T item) {
var function = ValueFunction;
return function == null ? null : function(item);
}
}
}
Then somewhere in your code, where you know T, eg you want to setup for MyClass
ValueHelper<MyClass>.ValueFunction = x => x.Value;
Then your list code becomes
foreach(var item in items)
{
value = ValueHelper<T>.GetValue(item);
}
If you have a control over T classes, you can introduce an interface with Value property and make every T class implement this interface. In that case you can enumerate list values like this:
foreach(IMyInterface item in items)
{
var someVar = item.VALUE;
//you know that item does have VALUE property and the type of that property as declared in interface
}
UPD. It works even if your T classes have different properties:
interface IMyInterface
{
string VALUE{get;set;}
}
class A : IMyInterface
{
public int Aprop{get;set;}
public string VALUE{get;set;}
}
class B : IMyInterface
{
public int Bprop{get;set;}
public string VALUE{get;set;}
}
If T types are known in advance then you can do this (not the best approach but those are already explained in other answers):
foreach(var item in List<T>)
{
if (item.GetType().Equals(typeof(fooClassA)))
{
ret = (item as fooClassA).VALUE_A;
}
if (item.GetType().Equals(typeof(fooClassB)))
{
ret = (item as fooClassB).VALUE_B;
}
....
}
Related
Recently, when handling collections of objects of the same (base-)class,
I´ve recently found myself writing something like this:
class SomeClass {
public bool PropertyA {get; set;}
}
class EncapsulatingClass {
private List<SomeClass> list = new();
private bool propA;
public bool PropertyA {
get { return propA; }
set {
propA = value;
foreach(SomeClass instance in list)
instance.PropertyA = value;
}
}
}
This is of course so I don´t have to use foreach every time I want to set a property for the collection. While this works fine, I feel like this requires a lot of code for something simple and a lot of repitition with each property.
Is there a better solution, like extracting the logic of "apply this for the property of the same name for each object in the list" into a function and just calling that in the setters?
There is the issue of ownership of the property. If you need to enforce synchronization such that setting PropertyA ins the encapsulating class, all the instances in the list also use the same value.
For example
class SomeClass
{
public SomeClass(EncapsulatingClass parent)
{
Parent=parent;
}
public EncapsulatingClass Parent { get; }
public bool PropertyA { get => Parent.PropertyA; }
}
class EncapsulatingClass
{
private List<SomeClass> list = new List<SomeClass>();
private bool propA;
public bool PropertyA
{
get { return propA; }
set
{
propA = value;
}
}
}
Otherwise, you have multiple PropertyA values, one for each instance, and then you have to decide which one is the master value, and what to do if some are different.
I'm wondering what it is you are doing to need this so often. It makes me think there's a flaw in the design of your application you could avoid by restructuring something but it's difficult to say without more information.
For your specific problem I would discard EncapsulatingClass and use the ForEach method on List<T> for a little more concise code:
myList.ForEach(s => s.PropertyA = true);
Alternatively, if you don't always use List<T> you can write your own extension method to work on all IEnumerables:
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var t in source)
action(t);
}
// Call it just like previously:
myIEnumerable.ForEach(s => s.PropertyA = true);
Of course, this is still cumbersome if you need to do it a lot. But I suspect if you do, it's probably a flaw in the design.
I might approach this with a custom List class providing a single mass update method.
public class EasyUpdateList<T> : List<T>
{
public void UpdateAll(Action<T> update)
{
if (update == null)
return;
foreach (T item in this)
update(item);
}
}
Now you don't need a specific encapsulating class, you can just create a new EasyUpdateList and update any number of properties across the collection using the UpdateAll method.
EasyUpdateList<MyClass> list = new EasyUpdateList<MyClass>();
list.Add(instance1);
list.Add(instance2);
...
list.UpdateAll(x =>
{
x.Property1 = "Value1";
x.Property2 = "Value2";
});
This still uses a foreach loop but is much more generic and you don't have to change your other classes or write repeated code for each one.
Of course you could also achieve this with an extension method for a List class if you don't want a new class.
public static void UpdateAll<T>(this IList<T> list, Action<T> update)
{
if (update == null)
return;
foreach (T item in list)
update(item);
}
I have two List<> with the same field that I need to edit. How to write a common function for these lists?
public List<?> CutField(List<?> list)
{
foreach(var element in list)
{
element.Field = // ;
}
return List<?>;
}
Best way would be using generics:
public List<T> CutField<T>(List<T> list) where T : MyInterface
{
foreach(T element in list)
{
element.Field = // ;
}
return list;
}
With
public interface MyInterface
{
object Field { get; set; } // or whatever datatype you need for the field
}
Of course all the possible types within your list should implement that interface.
As an aside you can also omit the return-type from CutField, as you´re already modifying the list passed as parameter.
Im trying to build an application where the properties of the classes are set based on the values in som XML files.
Some of the classes has properties consisting of a list of of it's children. Due to the way i made this program, the properties has to be set via propertyinfo classes. My problem is that i have trouble with fetcing the list of children (ICollection in Derived2). It must be cast to a generic list (ICollection OR HashSet), so i dont have to copy paste the same setChild method in each derived class.
I've tried casting the GetValue return value to either ICollection, HashSet or IENumerable, none worked.
Maybe the solution could be to use another method of the PropertyInfo class?
A somewhat simplified code example code:
public interface Superclass
{}
public class Derived1 : Superclass {}
public class Derived2 : Superclass
{
public Derived2()
{
PatientForloeb = new HashSet<Derived1>();
}
public virtual ICollection<Derived1>Derived1{ get; set; }
}
class Program
{
static void Main(string[] args)
{
List<Derived1> children = new List<Derived1>();
children.Add(new Derived1());
var parent = new Derived2();
setChild(parent, children);
}
private static void setChild(Superclass parent, List<Derived1> children)
{
foreach (var child in children)
{
var p = (parent.GetType().GetProperty(child.GetType().Name)); // This is ugly, should be based on type not name, but it works for my app.
var pi = p.GetValue(parent) as HashSet<Superclass>; ///////////<-------This gives null. This is the problem.
pi.add(child);
}
}
}
Superclass doesn't have a property, so actually the p is null.
Your property name is PatientForloeb not Derived1, maybe you are looking for this?
var p = parent
.GetType()
.GetProperties()
.First(x => x.PropertyType.GetGenericArguments()[0] == children.GetType().GetGenericArguments()[0]);
An HashSet<T> is an ICollection<T> but an ICollection<T> is not a HashSet.For example what would you expect to happen in this case:
var list = new List<int>();
var collection = list as ICollection<int>; // okey
var set = collection as HashSet<int>; // null
But that's not the only problem, because ICollection<T> is not covariant. Also, you don't even need to use as operator just get the value and set it.
In fact you don't even need to get value of your property.if you look at it carefully, you are getting the value of the property of your parent.And then trying to set that value back to parent.Even if that works, nothing will change.You need:
p.SetValue(parent, children);
I have class called GroupItem, i can store any type here say int, string, decimal, datetime etc.., Then, i have GroupItems which will store any groupItem. I'm using an arraylist to store all the groupItem.
public class GroupItem<T>
{
private string heading;
private List<T> items = new List<T>();
public GroupItem() { }
public string Heading
{
get { return heading; }
set { heading = value; }
}
public List<T> Items
{
get { return items; }
set { items = value; }
}
public void Add(T value)
{
this.items.Add(value);
}
public T this[int index]
{
get
{
return this.items[index];
}
}
}
public class GroupItems
{
private string groupName;
private List<object> items = new List<object>();
public string GroupName
{
get { return groupName; }
set { groupName = value; }
}
public GroupItems() { }
public void Add(object value)
{
this.items.Add(value);
}
public object this[int index]
{
get
{
return this.items[index];
}
}
}
I want to retrieve from GroupItems. How i can get generic item's values in groupItems?
I'm now inserting two items, datetime and int to groupitems. Now i want to retrieve groupitems[2] value but how i can convert this to groupItem without knowing what it is. Even we may get its genericarguments by getType().getGenericarguments()[0]. But how i can create an instance based upon that.
If the list is storing heterogeneous items, then I would suggest you need a common non-generic interface or base-class. So, say we have
interface IGroupItem {
// the non-generic members, and maybe
// "object Value {get;}" etc, and maybe
// "Type ItemTypr {get;}"
}
You would then have:
class GroupItem<T> : IGroupItem {...}
an you would then use
List<IGroupItem> ...
instead of ArrayList, or, franky, in place of GroupItems {...}
What I'd do is create a generic collection such as:
public class GroupItems<T> : List<GroupItem<T>>
{
}
If you need to extend the basic functionality of a list, you could also extend Collection<T> and override the methods you need:
public class GroupItems<T> : Collection<GroupItem<T>>
{
protected override void InsertItem(int index, T item)
{
// your custom code here
// ...
// and the actual insertion
base.InsertItem(index, item);
}
}
How about just replacing your GroupItems class with List<GroupItem<T>> ?
Depending on what you do with GroupItem you should either inherit from List/Collection as was offered by other or use a generic collection inside your class
e.g.
class GroupItem<T>
{
private List<T> items = new List<T>();
public void Add(T value)
{
items.Add(value);
}
public T Get()
{
//replace with some logic to detemine what to get
return items.First();
}
}
There are two situations that could be covered by your question:
You want to simply store a collection of GroupItem's of type T in the class GroupItems.
You want to store a collection of generic GroupItem's of any type in the class GroupItems. To better clarify, I mean that you could store GroupItem<DateTime> or GroupItem<int> in the same GroupItems class.
Here are some ways of going about storing and retrieving for both scenarios:
Same Type
public class GroupItem<T>
{
// ... Code for GroupItem<T>
}
public class GroupItems<T>
{
private List<GroupItem<T>> mItems = new List<GroupItem<T>>();
public void Add(T item)
{
mItems.Add(item);
}
public T GetItem(int index)
{
return mItems[index];
}
}
Here you will build a collections that contain GroupItem's of the same time, so a collection of GroupItem<DateTime> for example. All the items will be of the same type.
Generic Type
public interface IGroupItem
{
// ... Common GroupItem properties and methods
}
public class GroupItem<T>
{
// ... Code for GroupItem<T>
}
public class GroupItems
{
private List<IGroupItem> mItems = new List<IGroupItem>();
public void Add(IGroupItem item)
{
mItems.Add(item);
}
// This is a generic method to retrieve just any group item.
public IGroupItem GetItem(int index)
{
return mItems[index];
}
// This is a method that will get a group item at the specified index
// and then cast it to the specific group item type container.
public GroupItem<T> GetItem<T>(int index)
{
return (GroupItem<T>)mItems[index];
}
}
Here you will be able to build and maintain a single collection that can contain any GroupItem with any Type. So you could have a GroupItems collection that contains items of GroupItem<DateTime>, GroupItem<int>, etc.
Please note that none of these code examples take into account any erroneous circumstances.
Consider: you have a collection of items; the items may have any runtime type (string, int, etc.). Because of this, the static type of the collections items must be object.
It seems that you want to be able to retrieve items from the list with strong static typing. That's not possible without a lot of conditional logic (or reflection). For example:
object item = collection[0];
if (item is int)
//do something with an int
else if (item is string)
//do something with a string
Now suppose instead of "doing something" with the value of collection[0], we assign the value to a variable. We can do one of two things:
use the same variable for both cases, in which case the static type must be object.
use separate variables, in which case the static type will be string or int, but outside of the conditional logic, we can't know which variable holds the value of collection[0].
Neither option really solves the problem.
By creating GroupItem<T>, you add a level of indirection to this problem, but the underlying problem is still there. As an exercise, try reworking the example, but starting from "Consider: you have a collection of items; the items are of type GroupItem<T> where T may be any runtime type (string, int, etc.)."
Thanks for your inputs.
I have resolved it myself using multiple overloading methods to resolve this.
for example:
private void Print(GroupItem<string> items)
{
///custom coding
}
private void Print(GroupItem<int> items)
{
///custom coding
}
Though its not efficient enough, i want to do in this way as it was .net 2.0.
I'm now improving this in .Net 4.0 with new algorithm.
Thanks a lot for all of your helps.
I know there are very similar questions but im not sure that any of them are exactly what i need. I have 2 methods that do exactly the same thing (so i dont need to override or anything) the only difference is the parameter and return types.
public List<List<TestResult>> BatchResultsList(List<TestResult> objectList)
{
}
public List<List<ResultLinks>> BatchResultsList(List<ResultLinks> objectList)
{
}
is there a neat way of doing this that doesnt involve duplciate code (the types are used inside the method).
public List<List<T>> BatchResultsList<T>(List<T> objectList)
{
foreach(T t in objectList)
{
// do something with T.
// note that since the type of T isn't constrained, the compiler can't
// tell what properties and methods it has, so you can't do much with it
// except add it to a collection or compare it to another object.
}
}
and if you need to limit the type of T so that you'll only process specific sorts of objects, make both TestResult and ResultLinks implement an interface, say, IResult. Then:
public interface IResult
{
void DoSomething();
}
public class TestResult : IResult { ... }
public class ResultLinks : IResult { ... }
public List<List<T>> BatchResultsList<T>(List<T> objectList) where T : IResult
{
foreach(T t in objectList)
{
t.DoSomething();
// do something with T.
// note that since the type of T is constrained to types that implement
// IResult, you can access all properties and methods defined in IResult
// on the object t here
}
}
When you call the method, you can of course omit the type parameter, since it can be inferred:
List<TestResult> objectList = new List<TestResult>();
List<List<TestResult>> list = BatchResultsList(objectList);
use generic methods
public List<List<T>> BatchResultsList<T>(List<T> objectList)
{
}
when you call it for TestResult:
BatchResultsList<TestResult>(testResultList)
for ResultLinks:
BatchResultsList<ResultLinks>(resultLinksList)
EDIT:
I presume that because it's the same code inside you 2 methods, TestResult & ResultLinks must implement a common interface, let's call it SomeInterface & a common constructor, let's choose the parameterless one:
you would declare and use the method like this:
public List<List<T>> BatchResultsList<T>(List<T> objectList)
where T:SomeInterface, new()
{
List<List<T>> toReturn = new List<List<T>>();
//to instantiate a new T:
T t = new T();
foreach (T result in objectList)
{
//use result like a SomeInterface instance
}
//...
return toReturn;
}
what about
public List<IList> BatchResultsList(List<IList> objectList)
{
}
Generic version:
public List<List<T>> BatchResultsList<T>(List<T> objectList){}