Suppose I have a class that has a collection. I want to make a generic method to access certain types of objects within that collection. Basically what I want is:
Code:
class MyCollection
{
List<MyObject> storedObjects;
public T GetFirstObjectOfType<T>()
{
foreach(MyObject obj in storedObjects)
{
if(obj is T)
return (T) obj;
}
return null;
}
}
That is what I would like. The problem is when I try to compile it gives me an error:
Cannot convert type MyObject to 'T'
How can I get around this. I know that if I change it to:
Code:
public T GetFirstObjectOfType<T>() where T : MyObject
It will work, but now I am limited in the types that I can search for. For example if I want to search for an object that implements a specific interface I can't because that interface is not of type MyObject.
A class or OBJECT constraint should be sufficient (I would have to test to confirm)
TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
2008, 2009,2010 In theory, there is no difference between theory and practice; in practice there is.
* Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
* How NOT to post a question here
* Of course you read this carefully before you posted
* Need homework help? Read this first
Not sure what you mean by that. Can you elaborate?
Actually T MUST be derived from MyObject or the element could not be in the list in the first place....
But what I meant for a more general case:
Code:
T Get<T>()
where T : class
{
return (T) something;
}
or
Code:
T Get<T>()
where T : Object
{
return (T) something;
}
As I said, either a "class" or an "Object" constraint....
TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
2008, 2009,2010 In theory, there is no difference between theory and practice; in practice there is.
* Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
* How NOT to post a question here
* Of course you read this carefully before you posted
* Need homework help? Read this first
So in this case, the collection can contain instances of MyComparableObject because they are derived from MyObject. No problem. However I am not interested in instances of MyObject or MyComparableObject , I am interested in any and all objects that implement IComparable which happen to include MyComparableObject.
So using:
Code:
public T GetFirstObjectOfType<T>() where T : MyObject
Won't work because IComparable is not derived from MyObject. Sure I could do:
public class MyCollection {
List<object> storedObjects;
public T GetFirstObjectOfType<T>() where T:class{
foreach (object obj in storedObjects) {
T test = obj as T;
if (test != null){
return test;
}
}
return null;
}
}
This compiles (tested ) and shoul work IMHO
Last edited by JonnyPoet; October 28th, 2008 at 05:19 PM.
Jonny Poet
To be Alive is depending on the willingsness to help others and also to permit others to help you. So lets be alive. !
Using Code Tags makes the difference: Code is easier to read, so its easier to help. Do it like this: [CODE] Put Your Code here [/code]
If anyone felt he has got help, show it in rating the post.
Also dont forget to set a post which is fully answered to 'resolved'. For more details look to FAQ's about Forum Usage. BTW I'm using Framework 3.5 and you ? My latest articles : Creating a Dockable Panel-Controlmanager Using C#, Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
MyCollection coll = new MyCollection();
coll.Add(new A());
coll.Add(new D());
coll.Add(new C());
coll.Add(new B());
IMyInterface firstOne = coll.GetFirstObjectOfType<IMyInterface>();
Console.WriteLine("first One {0}", firstOne.GetName());
}
}
public class MyCollection {
List<object> storedObjects;
public MyCollection() {
storedObjects = new List<object>();
}
public T GetFirstObjectOfType<T>() where T:class{
foreach (object obj in storedObjects) {
T test = obj as T;
if (test != null){
return test;
}
}
return null;
}
public void Add(object x){
storedObjects.Add(x);
}
}
public class A {
private string _name;
public A(){
_name = "A";
}
public string GetName(){
return _name;
}
}
public class B:IMyInterface {
private string _name;
public B(){
_name = "B";
}
#region IMyInterface Member
public string GetName(){
return _name;
}
#endregion
}
public class C {
private string _name;
public C(){
_name = "C";
} public string GetName(){
return _name;
}
}
public class D :IMyInterface{
private string _name;
public D(){
_name = "D";
}
#region IMyInterface Member
public string GetName(){
return _name;
}
#endregion
}
public interface IMyInterface{
string GetName();
}
}
Tested - works
As you can see I created four simple similar classes. The difference is: only two of them containing the interface. The others have the same mathod, but it is not defined as to have the interface.
The result is that class 'D' is the first one in the list which is containing the interface. When I change the order in which I added the casses it always gives correct result.
I generally have used object instead of MyObject because MyObject itself restricts the objects you can store in your list as they need to derive from MyObject then.
Last edited by JonnyPoet; October 28th, 2008 at 05:19 PM.
Jonny Poet
To be Alive is depending on the willingsness to help others and also to permit others to help you. So lets be alive. !
Using Code Tags makes the difference: Code is easier to read, so its easier to help. Do it like this: [CODE] Put Your Code here [/code]
If anyone felt he has got help, show it in rating the post.
Also dont forget to set a post which is fully answered to 'resolved'. For more details look to FAQ's about Forum Usage. BTW I'm using Framework 3.5 and you ? My latest articles : Creating a Dockable Panel-Controlmanager Using C#, Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7
class MyCollection
{
List<MyObject> storedObjects;
public T GetFirstObjectOfType<T>()
{
foreach (MyObject obj in storedObjects)
{
if (obj is T)
return (T)(object)obj;
}
return default(T);
}
}
Just cast 'obj' to object before casting to 'T'.
If you don't add a generic constraint to the declaration which disallows value types, you'll have to change the 'return null' to 'return default(T)'.
NOTE: My code snippets are just snippets. They demonstrate an idea which can be adapted by you to solve your problem. They are not 100% complete and fully functional solutions equipped with error handling.
Brilliant. That was the trick. I am pretty sure that is why JonnyPoet's solution also worked because he was storing a list of objects rather than MyObject. But the casting to Object first does the trick and works perfectly for my situation (where switching the list to store objects is not acceptable).
Brilliant. That was the trick. I am pretty sure that is why JonnyPoet's solution also worked because he was storing a list of objects rather than MyObject. But the casting to Object first does the trick and works perfectly for my situation (where switching the list to store objects is not acceptable).
Thanks.
Glad you have a solution. I did just want to point out that:
Code:
X is Y;
;
if internally implemented along the line of
Code:
if (X == null)
return null;
Z tmp = X as Y;
if (tmp == null)
throw .....;
return tmp;
The point being is thart casting take significant overhead (unlike C++ where it is just a compiler feature, the runtime has to completely walk the meta data even for an explicit "hard" cast.
As a result the "IS" statement should typically only be used IF the result of the cast is NOT going to be used.
Have you tried???
Code:
T tmp = obj as T;
if (tmp != null)
return tmp;
TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
2008, 2009,2010 In theory, there is no difference between theory and practice; in practice there is.
* Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
* How NOT to post a question here
* Of course you read this carefully before you posted
* Need homework help? Read this first
Wiz yea, this is exactly what I suggested.Look in my two post I did before. Eggmann002 To make it totally clear: It works even if you use Myobject look here
Code:
public T GetFirstObjectOfType<T>() where T: class{
foreach (MyObject obj in storedObjects) {
T test = obj as T;
if (test != null) {
return test;
}
}
return null;
}
. The full example so you will see, it works is attached in the zip. I only had to derive all my example classes A,B,C,D from MyObject. The example only needs to restrict T to be a class, nothing else and that was told from WizBang also in one of the earlier posts. And because I got the idea, you didn't get him, I did a short example for you.
Last edited by JonnyPoet; October 29th, 2008 at 01:58 PM.
Jonny Poet
To be Alive is depending on the willingsness to help others and also to permit others to help you. So lets be alive. !
Using Code Tags makes the difference: Code is easier to read, so its easier to help. Do it like this: [CODE] Put Your Code here [/code]
If anyone felt he has got help, show it in rating the post.
Also dont forget to set a post which is fully answered to 'resolved'. For more details look to FAQ's about Forum Usage. BTW I'm using Framework 3.5 and you ? My latest articles : Creating a Dockable Panel-Controlmanager Using C#, Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7
Wiz yea, this is exactly what I suggested.Look in my two post I did before.
I know you did.
I was just adding that it is a faster solution than the hard cast(s) after using "IS".....
TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
2008, 2009,2010 In theory, there is no difference between theory and practice; in practice there is.
* Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
* How NOT to post a question here
* Of course you read this carefully before you posted
* Need homework help? Read this first
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.