[RESOLVED] Generic Methods without Where
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.
So for example if I wanted to do something like:
Code:
IDisposable disposableObject = collection.GetFirstObjectOfType<IDisposable>();
This won't work because IDisposable does not inherit MyObject.
Re: Generic Methods without Where
A class or OBJECT constraint should be sufficient (I would have to test to confirm)
Re: Generic Methods without Where
Quote:
Originally Posted by TheCPUWizard
A class or OBJECT constraint should be sufficient (I would have to test to confirm)
Not sure what you mean by that. Can you elaborate?
Re: Generic Methods without Where
Quote:
Originally Posted by Eggman002
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....
Re: Generic Methods without Where
Quote:
Originally Posted by TheCPUWizard
Actually T MUST be derived from MyObject or the element could not be in the list in the first place....
No it doesn't have to be derived from MyObject. Certainly the objects in the list have to be derived from MyObject, but T could be anything.
So I might have:
Code:
class MyComparableObject : MyObject, IComparable
{
}
Then I might want to do:
Code:
IComparable comparableObject = collection.GetFirstObjectOfType<IComparable>();
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:
Code:
IComparable comparableObject = collection.GetFirstObjectOfType<MyComparableObject>();
But again, that is not necessarily what I am looking for. I want IComparable.
Also using "where T : class" or "where T : Object" don't work. Actually where T : Object won't even compile because Object is a special class.
Re: Generic Methods without Where
Hi !
Whats about this one
Code:
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
Re: Generic Methods without Where
Here is the full test Console Application
Code:
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 :D :wave:
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.
Re: Generic Methods without Where
Code:
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)'.
Re: Generic Methods without Where
Quote:
Originally Posted by Mutant_Fruit
Just cast 'obj' to object before casting to 'T'.
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.
Re: Generic Methods without Where
Quote:
Originally Posted by Eggman002
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:
;
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;
1 Attachment(s)
Re: Generic Methods without Where
Quote:
Originally Posted by TheCPUWizard
...
Have you tried???
Code:
T tmp = obj as T;
if (tmp != null)
return tmp;
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.
Re: Generic Methods without Where
Quote:
Originally Posted by JonnyPoet
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".....