Doing Foreach construct on unknown types at runtime

I have a method which has a parameter of type IList<myType>.

I would like the method to determine what type is 'myType' (which I can already do),
then iterate over the list using a foreach construct. The problem is I cannot declare
the foreach(myType t in IList) because I don't have an object of the unknown type
myType passed in. If we knew that the type of 'myType' was type 'FooBar' then I could
write the following:
foreach(Foobar fb in myIList)
{
...do stuff
}

How can I get a the named type and use it as shown above?

thx,
ipaman
ipamanAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

dstanley9Commented:
Maybe I'm missing something, but this is how you use generic lists:

public void MyFunction(IList<myType> myIList)
{
  foreach(myType item in myIList)
  {
    // do something with the item
  }
}

are you trying to "cast" the item to another type that is related to myType?
0
ipamanAuthor Commented:
The problem is that 'myType is unknown at runtime.

'myType' is actually an interface that all objects implement. I want to be able to
figure out the type of 'myType' (which I can already do using .GetType()) and
then iterate over the list using the "Actual" type.

e.g.
main()
{
    IList<interfaceType> myList = new .....;
    myList.add_items_to_list();
    MyClass.DoMethod(myList);
}

class MyClass
{
  ...
  public void DoMethod(IList<interfaceType> myList)
  {
     Type  listType = myList[0].GetType();

     foreach (??? x in myList)
      {
         ...do stuff
      }
  }
}

Actual type would replace the ??? here.
0
dstanley9Commented:
You won't be able to do that because the foreach needs to know the type at compile time.  You'd have to use reflection to do anything other than what the interface provides, or explicitly try to cast to different types.  

How are you going to "do stuff" to an unknown type?  what kinds of "stuff" are you going to do?  could it be wrapped into the common interface?
0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

ipamanAuthor Commented:
So you are saying that there is no way to create an object via Activator.CreateInstance(..)
(or somthing) to use in the Foreach construct??
I could cast ut I would need a whopping switch or if else conditional to manage which
type I need to cast to.

In the end I will be accessing the properties (getter/setter) (using reflection) of the class type in the
IList.
0
WebstormCommented:
Hi ipaman,

If you can use interfaceType in your loop :
  public void DoMethod(IList<interfaceType> myList)
  {
     Type  listType = myList[0].GetType();

     foreach (interfaceType x in myList)
      {
         ...do stuff
      }
  }

In the loop, if you want to use specific functionnality of a specific class :
    if (x is ...type... )
           (x as ...type...).member ...
0
ipamanAuthor Commented:
WebStorm,

the foreach statement would have to have the type of object that implements the
interfaceType interface. The interface itself does not have the members I would be
interrogating. It is the classes that implement this interface that I need to "foreach" through.
0
ipamanAuthor Commented:
WebStorm,
inside the loop would be a gigantic if-else conditional to handle all the type that implement
the interface.
ipaman
0
dstanley9Commented:
But how are you going to know what properties to access if you don't know what type the object is?  
0
gregoryyoungCommented:
I am confused ...

"In the end I will be accessing the properties (getter/setter) (using reflection) of the class type in the
IList."

why do you need to iterate as the type then? :) you only need to cast to the type if you wanted to access something from that type ...

foreach(object o in MyList) {
   //do stuff with reflections ...
}

But if you are doing this why even use IList<T> when you can just use the non-generic IList and remove all confusion.

public void Iterate(IList List) {
    foreach(object o in List) {
        //do your stuff
    }
}

List<FooBar> list = new List<FooBar>();
list.Add(new FooBar());
Iterate(list);

the key being since you dont actually need anything off the conversion you shouldnt even be botherring to do it.

Cheers,

Greg
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
WebstormCommented:

If you want to access member variable, you should use methods you declare in the interface. So you can use the interface.
Otherwise you'll have to use multiple if tests.

Another way is to make this method a static method in each class :

  public static void DoMethod(IList<class> myList)
  {
     foreach (class x in myList)
      {
         ...do stuff
      }
  }
0
ipamanAuthor Commented:
dstanley9, exactly. I am trying to prevent using a big honkin' if-else conditional by doing something slick
like getting the type and creating it for use in the foreach constuct. From what I'm hearing, that is not possible.

gregoryyoung, I have to iterate as the class type because the interface does not define these...(unless I am confused about classes implementing interfaces. the implementating class takes on the type of the interface....correct?)... In your 'foreach' above the object o only sees the methods of the interface. I need to be able to see the methods of the impementing class so I can call the methods in the foreach (for any IList<interfaceType> type).


WebStorm, The interface wasn't designed to contain accessor methods. The accessor methods for
each subtype are different.
0
gregoryyoungCommented:
"gregoryyoung, I have to iterate as the class type because the interface does not define these...(unless I am confused about classes implementing interfaces. the implementating class takes on the type of the interface....correct?)... In your 'foreach' above the object o only sees the methods of the interface. I need to be able to see the methods of the impementing class so I can call the methods in the foreach (for any IList<interfaceType> type)"

your understanding of interfaces and types is wrong .. it will always be the same type when viewed through reflections ..

You said above you were only using reflections on the unknown type.

"In the end I will be accessing the properties (getter/setter) (using reflection) of the class type in the
IList."

I am confused now exactly what you are trying to do here. If you are using reflections you dont need to treat it as a certain type ... you would only need to do that if you wanted to access something in a typed way/
0
dstanley9Commented:
" getting the type and creating it for use in the foreach constuct. From what I'm hearing, that is not possible."

Well, technically it's possible using reflection, but you have to know what the type is in order to know what properties to access.  For example, suppose you have the following:

public interface ICommonMethods{
  void CommonMethod1();
  void CommonMethod2();
}

public class Impl1 : ICommonMethods{
  public void CommonMethod1() { return "foo"; }
  public void CommonMethod2() { return "bar"; }
  public string CustomProp1  {
    get    {
       return "CustomProp1";
    }
  }
}

public class Impl2 : ICommonMethods{
  public void CommonMethod1() { return "foo"; }
  public void CommonMethod2() { return "bar"; }
  public string CustomProp2  {
    get {
       return "CustomProp2";
    }
  }
}

Now _technically_ you can use reflection to call the properties CustomProp1 and CustomProp2 on each class, but if you don't know the type at design time, how are you going to know which properties to try and access?  You'd have to use a switch or if staments to see if the property exists on that class.

Now, if you want to use that interface as-is, but your implementations share common properties, you can either use a separate interface and have the classes implement both, ot you can define a new interface that inherits from the original:

public interface ICustomProperties: ICommonMethods  {
  string CustomProp1 {get};
  string CustmoProp2 {get};

}

Then your types would inherit from ICustomProperties and your list code would be:

  public void DoMethod(IList<ICustomProperties> myList)  {
     foreach (ICustomProperties x in myList)  {
         string s1 = x.CustomProp1;
         string s2 = x.CustomProp2;
         x.CommonMethod1();
         x.CommonMethod1();
      }
  }

0
ipamanAuthor Commented:
Take a look at my current pseudo code. Hopefully this will explain better than I have been.

interface IEntity{
long Id { get; set; }
}

public class foo : IEntity{
  public Int64 Id {
    get{ return id; }
    set{ id = value;}
  }
  public string Prop1{
     get{ return prop1; }
     set{ prop1 = value;}
  }
}
public class bar : IEntity{
  public Int64 Id {
    get{ return id; }
    set{ id = value;}
  }
  public string Prop2{
     get{ return prop2; }
     set{ prop2 = value;}
  }
}

public class driver{
  private IList<foo> list1 = new List<foo>();
  private IList<foo> list2 = new List<foo>();
  private IList<bar> list3 = new List<bar>();
  private IList<bar> list4 = new List<bar>();

  public driver()
  {
    BuildLists();
    // !!!!!!!! I could have passed in list3 and list 4 here instead.
    //.....that's why my ListComparer class doesn't know the type at runtime. !!!!!!!!!!
     ListComparer.Compare(list1, list2);
  }
  public void BuildLists()
  {
    //Let's pretend we set Prop1 on foo here before we added to the list.......
     list1.Add(new foo());
     list1.Add(new foo());
     list2.Add(new foo());
     list2.Add(new foo());
   
 //Let's pretend we set Prop2 on bar here before we added to the list.......
     list3.Add(new bar());
     list3.Add(new bar());
     list4.Add(new bar());
     list4.Add(new bar());
  }
}

public class ListComparer
{
   public static int Compare(IList<IEntity> x, IList<IEntity> y)
   {
      Type t = x[0].GetType(); //now I have the type of the IEntity in this case "foo"
     
      // Now I cannot do a foreach on this list because I don't have a class type to use in the foreach
      foreach( 'Type goes here' t in x)
      {
      }
   }
}
0
gregoryyoungCommented:
There is no code there that NEEDS the type from what you keep saying about using reflections ...

public class foo {
  public Int64 Id {
    get{ return id; }
    set{ id = value;}
  }
  public string Prop1{
     get{ return prop1; }
     set{ prop1 = value;}
  }
}
public class bar {
  public Int64 Id {
    get{ return id; }
    set{ id = value;}
  }
  public string Prop2{
     get{ return prop2; }
     set{ prop2 = value;}
  }
}

public class driver{
  private IList<foo> list1 = new List<foo>();
  private IList<foo> list2 = new List<foo>();
  private IList<bar> list3 = new List<bar>();
  private IList<bar> list4 = new List<bar>();

  public driver()
  {
    BuildLists();
    ListComparer.Compare(list1, list2);
  }
  public void BuildLists()
  {
    //Let's pretend we set Prop1 on foo here before we added to the list.......
     list1.Add(new foo());
     list1.Add(new foo());
     list2.Add(new foo());
     list2.Add(new foo());
   
 //Let's pretend we set Prop2 on bar here before we added to the list.......
     list3.Add(new bar());
     list3.Add(new bar());
     list4.Add(new bar());
     list4.Add(new bar());
  }
}

public class ListComparer
{
   public static int Compare(IList x, IList y)
   {
      // Now I cannot do a foreach on this list because I don't have a class type to use in the foreach
      foreach(object o in x)
      {
      }
   }
}

Of course since you are doing an equality compare here shouldnt you just be using the IComparable etc of the actual items? :) i.e. make each item able to compare itself to another item of its type .. then just iterate through the two lists telling the nodes to compare to each other .. and this whole problem goes away.

0
dstanley9Commented:
Actually this won't work at all as you can't cast IList<foo> to IList<IEntity> - even though you can cast foo to IEntity.  
0
dstanley9Commented:
But even so... within Compare how do you know whether to check the Prop1 property or Prop2 property?  You can do it using reflection, but you have to explicitly say which properties you check, so you're going to have a big switch or if block anyway?  
0
gregoryyoungCommented:
if each object is IComparable then it does the check itself ...

public class foo : IComparable {
  public Int64 Id {
    get{ return id; }
    set{ id = value;}
  }
  public string Prop1{
     get{ return prop1; }
     set{ prop1 = value;}
  }
  public integer CompareTo(object o) {
     foo f = o as foo;
     if(foo == null) throw new ArgumentException("o must be a foo");
     return this.Prop1.CompareTo(f.Prop1);
  }
}
public class bar :IComparable {
  public Int64 Id {
    get{ return id; }
    set{ id = value;}
  }
  public string Prop2{
     get{ return prop2; }
     set{ prop2 = value;}
  }
  public integer CompareTo(object o) {
     bar f = o as bar;
     if(bar == null) throw new ArgumentException("o must be a bar");
     return this.Prop2.CompareTo(f.Prop2);
  }
}


or you could pass in an IComparer to do the comparison ...

Cheers,

Greg
0
ipamanAuthor Commented:
dstanley9,

that's my point exactly. I am trying to do this generically but since I am hearing that it is impossible, I then have to have a gigantic switch (if-else) statement like I mentioned in my second comment.

gregoryyoung,
this question is not about whether or how to use IComparer. It is directed toward passing and using
ILists in a more generic way :-)
0
gregoryyoungCommented:
ipaman .. if you are ONLY using reflections you DONT NEED to cast it to a given type.

You are manufacturing a problem.

If you need to do things on the items you can use polymorphism on the items to do it. All of this without typing.

I cant say it enough that you dont need to be typing here and you certainly dont need a case statement.
0
ipamanAuthor Commented:
gregoryyoung,
ok then, if you have code that solves my situation (without modifying any code in the
implementing classes, i.e. class foo and bar) and allows the Compare method of ListComparer
class to take in an IList (of any type) and be able to call the methods of that type (i.e. foo.Prop1)
and not modifiy the Interface class by adding methods.......
then I will be greatful for an answer and will award the points.
thx,
ipaman
0
WebstormCommented:

To pass any generic list, you may use a generic method like this one :

public class ListComparer
{
   public static int Compare<T>(IList<T> x, IList<T> y)
   {
      // object type is T    
      foreach( T t in x )
      {
           // ...
      }
   }
}

But then, you need to know the property name you have to access :
   - change the name in foo & bar classes to have the same (Prop for example)
             t.Prop
   - or test each class in the loop using  is  &  as
   - or add access method in the ListComparer

public class ListComparer
{
      public static string GetProperty(foo o)
      { return o.Prop1; }
      public static string GetProperty(bar o)
      { return o.Prop2; }
}

->    GetProperty(t)
0
ipamanAuthor Commented:
WebStorm,

I cannot change the properties in the classes foo and bar. I wish I could but I do not have the authority
to do so. This wouldn't be a problem for me if the foo and bar classes had the exact
same proerty names:-) I wouldn't need to cast or manufacture any particular class type.

ipaman
0
gregoryyoungCommented:
ipaman please the the interface IComparer<T>

public class ListComparer<T>
{
   private Comparer<T> m_Comparer;
   public ListComparer(Comparer<T> _Comparer) {
        m_Comparer = _Comparer;
   }
   public  int Compare(IList<T> x, IList<T>)
   {
      // object type is T    
      foreach( T t in x )
      {
           foreach(T u in y) {
                bool same =  m_Comparer.Compare(t, u);
           }      
      }
   }
}

It will work with any Comparer<T> ... just pass it in the constructor.

0
gregoryyoungCommented:
I would like to know why the answer given "does not work"
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.