How do I iterate a generic reflected method? - c#

In my CMS I have a load of modules which allow me to do some clever item listing stuff. I am trying to use them to pull out a list of their child objects via reflection, but am getting stuck with the level of generics involved.
I have got as far as this method:
var myList = moduleObj.GetType().GetMethod("ChildItems").Invoke(moduleObj, new object[] { });
which returns a List. Each modulespecificobject is bound it an IItemListable interface which has the methods in it I am trying to access.
I am unsure how I can cast or iterate the myList object as a set of IItemListable objects access the methods required.
Thanks
A few of the classes:
public interface IItemListable
{
IQueryable GetQueryableList();
string GetIDAsString();
IItemListable GetItemFromUrl(string url, List<IItemListable> additionalItems);
bool IsNewItem();
IItemListable CreateItem<T>(ItemListerControl<T> parentList) where T : class, IItemListable;
IItemListable LoadItem(string id);
IItemListable SaveItem();
RssToolkit.Rss.RssItem ToRssItem();
void DeleteItem();
string ItemUrl();
}
public interface IItemListModule<T> where T: IItemListable
{
List<T> ChildItems();
}
public class ArticlesModule : ItemListModuleBase<Article>, IItemListModule<Article>
{
#region IItemListModule<Article> Members
public new List<Article> ChildItems()
{
return base.ChildItems().Cast<Article>().Where(a => a.IsLive).ToList();
}
#endregion
}

You can direct cast while iterating:
IList myList = (IList)moduleObj.GetType().GetMethod(
"ChildItems").Invoke(moduleObj, new object[] { });
foreach (IItemListable o in myList)
{
}
Edit: I would better mark ChildItems as virtual in the base then you could write
public override List<Article> ChildItems()
{
return base.ChildItems().Where(a => a.IsLive).ToList();
}
and
var myList = moduleObj.ChildItems();
foreach (IItemListable o in myList)
{
}
without any need to cast, avoiding the use of the new keyword and without having to use reflection.

Maybe this will help:
http://devlicio.us/blogs/louhaskett/archive/2007/06/13/how-to-cast-between-list-t-s.aspx
(Also some extra links in the comments)

Related

Get list of property names using interface method

I have two custom types Customer and Employee which implement the interface ITablefy. This interface has only one method, GetPropertyList which returns a list of strings of the property names of the object that implements it. I have a web service which looks like:
public string ReturnPropertyNames(ITablefy i)
{
List<string> propList = new List<string>();
TableFactory factory = new TableFactory();
ITablefy table = factory.CreateTable(i);
propList = table.GetPropertyList(table);
return propList[1];
}
so in this example the Factory creates a concrete type that implements ITablefy
I realized when I had a problem when both of my classes Customer and Employee implemented their GetPropertyList methods exactly the same:
//property list is a private member variable in each class
public List<string> GetPropertyList(ITablefy i)
{
TableFactory factory = new TableFactory();
ITablefy table = factory.CreateTable(i);
foreach (var propInfo in table.GetType().GetProperties())
{
propertyList.Add(propInfo.Name);
}
return propertyList;
}
Rather than copy and paste that code I'm looking for a better solution to what I have currently. If I only want certain types to use the GetPropertyList method how can I control that without having to copy and paste this same code? Harcoding the type to create in each class doesn't seem like a good solution to me. Employee and Customer don't logically make sense to use inheritance either. What's a proper solution for something like this?
factory:
public class TableFactory
{
public ITablefy CreateTable(ITablefy i)
{
if (i is Employee)
{
return new Employee();
}
else if (i is Customer)
{
return new Customer();
}
else
{
return null;
}
}
}
public static List<string> GetPropertyNames(this Object o)
{
List<string> names = new List<string>
foreach (PropertyInfo prop in o.GetType().GetProperties())
names.Add(prop.Name);
return names;
}
Now you can implement ITablefy in terms of any object.GetPropertyNames() using the extension method above.
There are a few questions that comes to my mind:
If It's so easy to do generically, why are you even using the interface?
Shouldn't you be checking properties for public accessors?
Shouldn't your interface be returning a more general type like IEnumerable<string> or ICollection<string>?
Wouldn't the interface be better designed to filter out property names that you don't want? That way you could assume all public properties are part of the set except those that aren't.
You make the interface be something like:
public interface IPropertyInfoFilterProvider {
public Func<PropertyInfo, bool> PropertyInfoSkipFilter { get; set; }
}
or
public interface IPropertyNameFilterProvider {
public Func<string, bool> PropertyNameSkipFilter { get; set; }
}
and then you can initialize the default to (prop) => false.
so now you can harvest the property names automagically and in one place and let implementations determine what gets taken and what doesn't and your harvesting code could use that filter in a linq where clause.
You could make it an extension method on ITablefy.
Or a static method on ITablefy

Convert List<T> to List<object>

I have a problem with the generic class. I have something like this:
public abstract class IGroup<T> : IEnumerable where T : class {
protected List<T> groupMembers;
protected List<IGameAction> groupIGameActionList;
public IGroup() {
groupMembers = new List<T>();
groupIGameActionList = new List<IGameAction>();
//groupIGameActionList.Add(new DieGameAction(groupMembers));
}
}
And second class:
class DieGameAction : IGameAction {
List<object> gameObjectList;
public DieGameAction(List<object> objectList) {
gameObjectList = objectList;
}
}
I don't know how to cast or convert groupMembers in commented line. This doesn't work because it can not be converted (List<T> to List<object>). So how can I do it?
groupMembers.Cast<object>().ToList();
But that doesn't look a good thing to do. You are creating a new empty list that will not be related to the original anymore.
The way you're gonna be using these classes will tell if that would be a good idea.
If you're planning to have both lists updated by adding items to a single class, it will not fit. Then maybe your DieGameAction should be generic as well: DieGameAction<T>.
Then you could give the original list without casting.
But, there's another danger: if you set a new list to the IGroup, it will not be reflected to DieGameAction.
So, it all depends on what you're trying to do.
Old question but by declaring your variable as IList instead of List<object>, you can assign a list (or array) of any type to the variable and simply cast it to List<Whatever> later (of course it's going to throw an exception if you cast it to a wrong type). I have found this more efficient than having to do .Cast<object>() every time you want to assign something to the variable.
I'm going to focus only on providing a solution.
You can make DieGameAction use IList < object > instead:
class DieGameAction : IGameAction {
IList<object> gameObjectList;
public DieGameAction(IList<object> objectList) {
gameObjectList = objectList;
}
}
Then you can provide an IList < object > implementation which adapts any IList < T >.
public abstract class IGroup<T> : IEnumerable where T : class {
protected List<T> groupMembers;
protected List<IGameAction> groupIGameActionList;
public IGroup() {
groupMembers = new List<T>();
groupIGameActionList = new List<IGameAction>();
groupIGameActionList.Add(new DieGameAction(new ObjectListAdapter<T>(groupMembers)));
}
}
I'm going to try and provide one of the many possible solutions using as base the System.Collections.ObjectModel.Collection < T > which can also wrap an IList < T >:
public class ObjectListAdapter<T> : System.Collections.ObjectModel.Collection<T>, IList<object>
{
public ObjectListAdapter(IList<T> wrappedList)
: base(wrappedList)
{
}
public int IndexOf(object item)
{
return base.IndexOf((T)item);
}
public void Insert(int index, object item)
{
base.Insert(index, (T)item);
}
public new object this[int index]
{
get
{
return base[index];
}
set
{
base[index] = (T)value;
}
}
public void Add(object item)
{
base.Add((T)item);
}
public bool Contains(object item)
{
return base.Contains((T)item);
}
public void CopyTo(object[] array, int arrayIndex)
{
this.Cast<object>().ToArray().CopyTo(array, arrayIndex);
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(object item)
{
return base.Remove((T)item);
}
public new IEnumerator<object> GetEnumerator()
{
return this.Cast<object>().GetEnumerator();
}
}
The list changes will throw a type casting exception upon trying to use an unsupported object, the way I programmed it over here, but you can also handle that as you like.
Now, for IList < object > you could also try using IList instead which is also implemented by List < T > so you'll basically have to do nothing more to get this working.
Note that the important thing is that the list will appear the same at both places used since they will basically be using the same underlying List object.
Let me know if this answers your question, by marking it as an answer, or not to refrain :)
I just faced the same problem which led me here. The solution that worked for me was to cast into IEnumerable of Object instead of List of Object
(System.Collections.Generic.IEnumerable<object>)groupMembers;
I had similar issue today but i called the LINQ .ToArray() on it directly and it works fine. that should be shorter than casting.
so you could say
groupMembers.ToArray();
It worked for me like this:
List<myclass> listMyclass = new List<myclass>();
var listObject = listMyclass.ToList<object>();

Generic type's causing issue C#.net

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.

Casting an object to a base collection

I'm not totally convinced this is possible, but here goes. I have a method returning an object, although the actual type is Collection. Now, I can easily cast the object into the collection using
var myCollection = myObject as Collection<MyClassA>;
However the problem I have is that Collection<MyClassA> could alternatively be Collection<MyClassB> or Collection<MyClassC>. All of these MyClassX's are inherited from MyBaseClass, so ideally I would like to be able to do something like
var myCollection = myObject as Collection<MyBaseClass>;
However this throws an exception when casting. Is it possible to do this in anyway? I understand that it may be within .Net 4?
Thanks for the help.
EDIT:
OK - The answers so far are very useful, however they only solve the second part of the solution - converting/casting collections.
I am still unsure as to how I should initially cast the object to a collection (without the use of a huge if statement for each of the possible types)
This is only supported with IEnumerable<T> in .NET 4. Check out the difference in the signatures:
IEnumerable<T>:
public interface IEnumerable<out T> : IEnumerable
Collection<T>:
public class Collection<T> : IList<T>,
ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
That out keyword in the type parameter is what tells .NET to support variance.
Before I had access to .NET 4 I wrote an extension method that achieved this:
public static IEnumerable<U> CastCollection<T, U>(this IList<T> items) where U : class
{
var collection = new List<U>();
foreach (var item in items)
{
if (item is U)
{
var newItem = item as U;
collection.Add(newItem);
}
}
return collection;
}
You would use it like this:
var myCollection = myObject.CastCollection<MyClassA, MyBaseClass>();
myCollection will be an IEnumerable<MyBaseClass> in this case.
Alternate solution: you could use interfaces and generics to get what you want.
public interface IMyClass
{
}
public class MyClassA : IMyClass
{
}
public class MyClassB : IMyClass
{
}
public class MyClassC : IMyClass
{
}
static void Main(string[] args)
{
var listA = new List<IMyClass>{new MyClassA{}, new MyClassA{}};
var listB = new List<IMyClass> { new MyClassB { }, new MyClassB { } };
var listC = new List<IMyClass> { new MyClassC { }, new MyClassC { } };
List<IMyClass> genericList = listA.Cast<IMyClass>().ToList();
}
Something like this will compile properly and also allow you to assign different lists of any types that implement the common interface, to the same variable (in this case genericList.
This cannot be done by casting the collection as a whole. However, you can cast the individual elements to a new collection. Look at LINQ's Cast<> extension method.

Using a class derived from generic list with LINQ

I have two classes, CheckboxItemsList which extends a generic list, and CheckboxItems, which contains a list of objects of type CheckboxItem.
I want to use LINQ to be able to filter CheckboxItemsList based on properties of its CheckboxItems objects. The return type is always a generic list, though, but I want it to be a CheckboxItemsList.
So I guess the basic question is, can linq be made to return a list of the same type that it starts with? Since I can't cast a base class to a derived class, do I have any option other than iterating through the results of the linq query and rebuilding the derived list object row by row? Not that this is the end of the world, but I'm relatively new to linq and was wondering it there is a better way to do it.
What I want:
CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed);
(obviously doesn't work since the query will return List<CheckboxItems>, not CheckboxItemsList)
The objects, generally:
public class CheckboxItemsList: List<CheckboxItems>
{
// does not add any fields, just access methods
}
public class CheckboxItems : IEnumerable<CheckboxItem>
{
public long PrimaryKey=0;
protected CheckboxItem[] InnerList;
public bool Changed
{
get {
return (InnerList.Any(item => item.Changed));
}
}
....
}
No, this is not possible out of the box. You'll need to add code to do this.
For example, you can add a constructor like so:
public CheckboxItemsList(IEnumerable<CheckboxItems> checkboxItems) {
// something happens
}
Then you can say
CheckboxItemsList newList = new CheckboxItemsList(
MyCheckboxItemsList.Where(item => item.Changed)
);
Additionally, you could add an extension method like so
static class IEnumerableCheckboxItemsExtensions {
public static ToCheckboxItemsList(
this IEnumerable<CheckboxItems> checkboxItems
) {
return new CheckboxItemsList(checkboxItems);
}
}
and then
CheckboxItemsList newList =
MyCheckboxItemsList.Where(item => item.Changed)
.ToCheckboxItemsList();
LINQ works on IEnumerable<T> and IQueryable<T> and the result types of all LINQ operations (Where, Select) etc, will return one of those. The standard ToList function returns a concrete list of type List<T>, you may need to come up with an extension method, e.g.:
public static CheckboxItemsList ToItemList(this IEnumerable<CheckboxItem> enumerable)
{
return new CheckboxItemsList(enumerable);
}
No, there's no built-in way to do this. You have two main options:
Add a constructor to your CheckboxItemsList class that takes an IEnumerable<CheckboxItems> or similar. Pass that collection on to the base List<T> constructor that takes an IEnumerable<T>. That base constructor should then populate the list for you:
var newList =
new CheckboxItemsList(MyCheckboxItemsList.Where(item=>item.Changed));
// ...
public class CheckboxItemsList : List<CheckboxItems>
{
public CheckboxItemsList(IEnumerable<CheckboxItems> collection)
: base(collection)
{
}
}
Create an extension method that takes an IEnumerable<CheckboxItems> or similar and returns a populated CheckboxItemsList:
var newList = MyCheckboxItemsList.Where(item=>item.Changed)
.ToCheckboxItemsList();
// ...
public static class EnumerableExtensions
{
public static CheckboxItemsList ToCheckboxItemsList(
this IEnumerable<CheckboxItems> source)
{
var list = new CheckboxItemsList();
foreach (T item in source)
{
list.Add(item);
}
return list;
}
}
(Of course, for completeness you could implement both of these options. The extension method would then just pass its IEnumerable<CheckboxItems> argument on to the constructor rather than manually looping and adding each item.)
You can also use "Conversion Operator", as below:
public class CheckboxItemsList: List<CheckboxItems>
{
public static implicit operator CheckboxItems(IEnumerable<CheckboxItems> items)
{
var list = new CheckboxItemsList();
foreach (var item in items)
{
list.Add(item);
}
return list;
}
}
Now, the below code would work.
CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed);
From MSDN:
A conversion operator declaration that includes the implicit keyword introduces a user-defined implicit conversion. Implicit conversions can occur in a variety of situations, including function member invocations, cast expressions, and assignments. This is described further in Section 6.1.
A conversion operator declaration that includes the explicit keyword introduces a user-defined explicit conversion. Explicit conversions can occur in cast expressions, and are described further in Section 6.2.
Here is what I came up with, building on the various suggestions of others. A generic extension method:
public static T ToList<T>(this IEnumerable baseList) where T : IList,new()
{
T newList = new T();
foreach (object obj in baseList)
{
newList.Add(obj);
}
return (newList);
}
So now I can do what I want:
CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed)
.ToList<CheckboxItemsList>();
Another pretty obvious solution occurred to me, which is also useful for situations where the derived list class has field properties that I need to maintain in the new list.
Just create a new instance of my derived list class, and use AddRange to populate it.
// When created with a CheckboxItemsList parameter, it creates a new empty
// list but copies fields
CheckboxItemsList newList = new CheckboxItemsList(OriginalList);
newList.AddRange(OriginalList.Where(item => item.Changed));

Categories

Resources