943,942 Members | Top Members by Rank

Ad:
  • C# Discussion Thread
  • Unsolved
  • Views: 1246
  • C# RSS
Oct 8th, 2009
0

Problem casting generic object to specific object

Expand Post »
I've created the following generic method
C# Syntax (Toggle Plain Text)
  1. protected int GetSpecifiedIndexByName<T>(T collection, string itemName)
  2. {
  3. int count = 0;
  4. foreach (MyElement claim in collection)
  5. {
  6. if (itemName.Equals(claim.Name))
  7. {
  8. return count;
  9. }
  10. count++;
  11. }
  12. }

Which is called by

C# Syntax (Toggle Plain Text)
  1. int index = GetSpecifiedIndexByName<MyCollection>(claimColl, itemName);

However, when I compile this I get the error

Error 1 foreach statement cannot operate on variables of type 'T' because 'T' does not contain a public definition for 'GetEnumerator'

I cannot cast the generic collection to the known collection directly i.e.

C# Syntax (Toggle Plain Text)
  1. MyCollection foo = (MyCollection)collection;

But have to take the intermediary step

C# Syntax (Toggle Plain Text)
  1. Object foo = collection;
  2. MyCollection foobar = (MyCollection)foo;

This is clearly a lack of understanding about generics (and my 1st attempt at it) but any answers relating to why I get the problems (and solution) would be much appreciated.

Thanks

Dhaval
Similar Threads
Reputation Points: 10
Solved Threads: 0
Newbie Poster
dhaval_shah is offline Offline
2 posts
since Oct 2009
Oct 8th, 2009
0
Re: Problem casting generic object to specific object
Upload a sample project demonstrating this behavior. You can upload a project by clicking on "Go Advanced" and then "Manager Attachments". You need to implement IEnumerable to use foreach() .
Featured Poster
Reputation Points: 1749
Solved Threads: 735
Senior Poster
sknake is offline Offline
3,948 posts
since Feb 2009
Oct 8th, 2009
4
Re: Problem casting generic object to specific object
I've created the following generic method
C# Syntax (Toggle Plain Text)
  1. protected int GetSpecifiedIndexByName<T>(T collection, string itemName)
  2. {
  3. int count = 0;
  4. foreach (MyElement claim in collection)
  5. {
  6. if (itemName.Equals(claim.Name))
  7. {
  8. return count;
  9. }
  10. count++;
  11. }
  12. }
You have two problems with this method. One is that there is no proof that T : IEnumerable. You need to use a where clause to specify that. The other problem is that not all control paths lead to a return statement.

You shouldn't be using generics for this kind of behavior. Instead, you should just have the function take an object that implements the IEnumerable interface:
C# Syntax (Toggle Plain Text)
  1. protected int GetSpecifiedIndexByName(IEnumerable collection, string itemName)
  2. {
  3. int count = 0;
  4. foreach (MyElement claim in collection)
  5. {
  6. if (itemName.Equals(claim.Name))
  7. {
  8. return count;
  9. }
  10. count++;
  11. }
  12. return -1;
  13. }
You could also use IEnumerable<MyElement> in the signature. This is a good idea because it more tightly defines the interface of the function.
C# Syntax (Toggle Plain Text)
  1. protected int GetSpecifiedIndexByName(IEnumerable<MyElement> collection, string itemName)
  2. {
  3. ...
  4. }

So, you should not be trying to implement a generic function at all. You just want a function that takes a parameter of type IEnumerable<MyElement>.

Quote ...
I cannot cast the generic collection to the known collection directly i.e.
In general, you can't cast from one type to an unrelated type. For example, you can't cast something from Int32 to ArrayList. This is because there's no way that can be correct! Similarly, you can't cast a generic type, which could be anything, to the type MyCollection. You can only cast things to superclasses and subclasses of the type you're casting.

Quote ...
But have to take the intermediary step

C# Syntax (Toggle Plain Text)
  1. Object foo = collection;
  2. MyCollection foobar = (MyCollection)foo;
In this example, you've cast up to Object (which is allowed because Object is a superclass of everything) and then you've cast down to MyCollection (which is allowed because MyCollection is a subclass of Object). The fact that you wish to do such a thing means you're trying to use the type system the wrong way, and I've already described how.

By the way, here's another possible way to write the function you want. It uses the where clause that I mentioned at the beginning of my reply. This would be a spurious use of generics, though, since generics are only useful when you want to prove that two types are equal.

C# Syntax (Toggle Plain Text)
  1. protected int GetSpecifiedIndexByName<T>(T collection, string itemName)
  2. where T : IEnumerable<MyElement>
  3. {
  4. int count = 0;
  5. foreach (MyElement claim in collection)
  6. {
  7. if (itemName.Equals(claim.Name))
  8. {
  9. return count;
  10. }
  11. count++;
  12. }
  13. return -1;
  14. }
Team Colleague
Reputation Points: 1135
Solved Threads: 172
Super Senior Demiposter
Rashakil Fol is offline Offline
2,479 posts
since Jun 2005
Oct 8th, 2009
0
Re: Problem casting generic object to specific object
IEnumerable, which supports a simple iteration over a collection of a specified type.

C# Syntax (Toggle Plain Text)
  1. protected int GetSpecifiedIndexByName<T>(T collection, string itemName) {
  2. int count = 0;
  3. foreach (MyElement claim in collection as IEnumerable<MyElement>){
  4. if (itemName.Equals(claim.Name)){
  5. return count;
  6. }
  7. count++;
  8. }
  9. return count;
  10. }
Moderator
Reputation Points: 2136
Solved Threads: 1228
Posting Genius
adatapost is offline Offline
6,527 posts
since Oct 2008
Oct 9th, 2009
-1
Re: Problem casting generic object to specific object
Thanks for the replies.

The suggestion I liked

C# Syntax (Toggle Plain Text)
  1. foreach (MyElement claim in collection as IEnumerable<MyElement>){

returns a

System.NullReferenceException : Object reference not set to an instance of an object.

I assume in this case because this is because we don't know what the collection passed in is at runtime?

To put into context what I'm trying to do, I want to have one method which can handle two sets of collections which both extend IEnumerable and both of which collections have their own results elements i.e. in HelloWorldCollection

C# Syntax (Toggle Plain Text)
  1. public MyElement this[int index]
  2. {
  3. get { return (MyElement)ElementRaw(index); }
  4. }

which returns a MyElement object and similarly for FooBarCollection, a FooElement can be returned. Rather than writing two separate methods (or in my case below, one method with two separate for loops dependent on collection type) is there a better way I can implement this? Or, in short, as said earlier, this isn't a good use of generics and shaft this idea completely? Note that HelloWorldCollection and FooBar Collection both extend MyFooCollection.

C# Syntax (Toggle Plain Text)
  1. protected int GetSpecifiedIndexByName<T>(T collection, string itemName)
  2. where T : MyFooCollection
  3. {
  4. int count = 0;
  5. if (collection is HelloWorldCollection) {
  6.  
  7. foreach (MyElement claim in collection)
  8. {
  9. if (itemName.Equals(claim.Name))
  10. {
  11. return count;
  12. }
  13. count++;
  14. }
  15. }
  16.  
  17. else if (collection is FooBarCollection)
  18. {
  19. foreach (FooElement commission in collection)
  20. {
  21. if (itemName.Equals(commission.Name))
  22. {
  23. return count;
  24. }
  25. count++;
  26. }
  27. }
  28.  
  29. throw new ApplicationException("Type with name " + itemName + " not found");
  30. }
Last edited by dhaval_shah; Oct 9th, 2009 at 8:08 am. Reason: Additional notes on thread
Reputation Points: 10
Solved Threads: 0
Newbie Poster
dhaval_shah is offline Offline
2 posts
since Oct 2009

This thread is more than three months old

No one has posted to this discussion for at least three months. Please let old threads die and do not reply to them unless you feel you have something new and valuable to contribute that absolutely must be added to make the discussion complete. Otherwise, please start a new thread in this forum instead.
Message:
Previous Thread in C# Forum Timeline: Validations in textbox
Next Thread in C# Forum Timeline: Comparing values inside TextBoxes( which is present inside a GridView)





About Us | Contact Us | Advertise | Acceptable Use Policy
Forum Index | Build Custom RSS Feed


Follow us on Twitter


© 2011 DaniWeb® LLC