Generic method to return object reference

A

acb

Hi,

I have a list of different objects in a <List> Structure. There is only
one category of each kind of object.

Current I have the following methods:

public static Flag GetFlagObj()
{
foreach (Thingy s in _Thingies)
{
if (s is Flag)
return (Flag)s;
}
return null;
}

public static Cloth GetFlagObj()
{
foreach (Thingy s in _Thingies)
{
if (s is Cloth)
return (Cloth)s;
}
return null;
}

public static BedSprd GetFlagObj()
{
foreach (Thingy s in _Thingies)
{
if (s is BedSprd)
return (BedSprd)s;
}
return null;
}


Is there a way I could have one generic method that would take as a
parameter the item I wish returned?

Thank you for your help.
Al
 
J

Joanna Carter [TeamB]

"acb" <[email protected]> a écrit dans le message de (e-mail address removed)...

| I have a list of different objects in a <List> Structure. There is only
| one category of each kind of object.
|
| Current I have the following methods:
|
| public static Flag GetFlagObj()
| {
| foreach (Thingy s in _Thingies)
| {
| if (s is Flag)
| return (Flag)s;
| }
| return null;
| }
|
| public static Cloth GetFlagObj()
| {
| foreach (Thingy s in _Thingies)
| {
| if (s is Cloth)
| return (Cloth)s;
| }
| return null;
| }
|
| public static BedSprd GetFlagObj()
| {
| foreach (Thingy s in _Thingies)
| {
| if (s is BedSprd)
| return (BedSprd)s;
| }
| return null;
| }
|
|
| Is there a way I could have one generic method that would take as a
| parameter the item I wish returned?

Yes, you do it like this :

public static T GetObj<T>()
{
foreach (Thingy s in _Thingies)
{
if (s is T)
return (T) s;
}
return default(T);
}

Joanna
 
V

Vladimir Matveev

possible solution: create generic search method with argument of
required type, disadvantage of this method - generic return value

static List<object> _list = new List<object>();

public static object Find(Type t)
{
return _list.Find(delegate(object obj)
{
return t.IsAssignableFrom(obj.GetType());
});
}
 
M

Marc Gravell

As an extension to this; if you are going to have a large number of items
(each of a different type, as suggested by GetObj<T> [GetThingy<T>()
perhaps?]) you could improve performance by using a Dictionary<Type,
Thingy>; when adding you use obj.GetType() as the key, and when searching
you use typeof(T) - this then gives you hashtable performance.

Also - if thingies can be added / removed outside of the static ctor, I
would strongly advise making this (static) data thread-safe - e.g.

private static Dictionary<Type, Thingy> _Thingies; // init in static ctor

public static T GetThingy<T>()
{
lock(_Thingies) {
return (T) _Thingies[typeof(T)];
}
}

public static void Add(Thingy thingy) {
if(thingy==null) throw new ArgumentNullException("thingy"); // need a
non-null thingy to call GetType()
lock(_Thingies) {
_Thingies.Add(thingy.GetType(), thingy);
}
}

// or - particularly if you accept null values for thingy
public static void Add<T>(T thingy) where T : Thingy {
lock(_Thingies) {
_Thingies.Add(typeof(T), thingy);
}
}

(or something like that; code not tested)

Marc
 
V

Vladimir Matveev

static List<object> _list = new List<object>();

public static T Find<T>()
{
return (T)_list.Find(delegate(object obj)
{
return (obj is T);
});
}
 
M

Marc Gravell

not important, but I omitted a useful where clause:

public static T GetThingy<T>() where T : Thingy { //...
}

Marc
 
J

Joanna Carter [TeamB]

"Marc Gravell" <[email protected]> a écrit dans le message de (e-mail address removed)...

| As an extension to this; if you are going to have a large number of items
| (each of a different type, as suggested by GetObj<T> [GetThingy<T>()
| perhaps?]) you could improve performance by using a Dictionary<Type,
| Thingy>; when adding you use obj.GetType() as the key, and when searching
| you use typeof(T) - this then gives you hashtable performance.

Excellent addenda :))

Joanna
 
N

Nick Hounsome

Some people get a new toy and they just have to use it everywhere!

For the example that you give generics are totally unnecessary and overloads
with "out" parameters will do the job and save you having to type in the
type name in the call.

public static void Get(out X x)
{
foreach(Thingy t in _Thingies)
{
x = t as X;
if( x != null )
return;
}
x = null;
}

X x;
list.Get(out x);
 
M

Marc Gravell

I'm not sure that your example makes sense here... the original question was
to have a function where the main difference between calls was the type of
thingy (Flag, Cloth, etc). You've essentially written a version that will
*only* gets 1 type: X - i.e. very similar to the code in the OP. If you want
X to be variable, then (unless I'm being really, really slow) you *need*
this to be a generic - i.e. Get<X>

However! You do raise an interesting point; if I refactored this into a
standard TryGet format (but with generics), then I actually *don't* need to
specify T, since this will be inferred by the compiler (via the out param):

public static bool TryGet<T>(out T thingy) where T : Thingy {
lock(_Thingies) {
return _Thingies.TryGet(typeof(T), out thingy);
}
}

I should then be able to call

Flag f;
MyStaticClass.TryGet(out f);

This will then infer <Flag> since f is declared as <Flag>

Marc
 
M

Marc Gravell

(previous code didn't compile: this does)

public static bool TryGet<T>(out T thingy) where T : Thingy {
bool found;
Thingy foundItem;
lock (_Thingies) {
found = _Thingies.TryGetValue(typeof(T), out foundItem);
}
thingy = (T)foundItem;
return found;
}
 
M

Marc Gravell

Oh right, I see what you're doing; OK, further to the parallel post I'll
agree it does work - but it's a lot of repeated code, plus it makes the
calling symantecs a little tricker.

Personally, I'd rather have:

Flag f = MyStaticClass.Get<Flag>();

than either your or my version of:

Flag f;
MyStaticClass.Get(out f);

Marc
 
A

acb

Thank you to everyone for your input; you've help me learn (still to
fully understand :) somthing new.
 
J

Jay B. Harlow [MVP - Outlook]

acb,
As the others have shown you can define a method with a parameterized return
type.

However! You need to supply the type parameter when you call the method
directly, something like:

object o = doSomething<object>();
MemoryStream m = doSomething<MemoryStream>();

Further! it "violates" an FxCop rule as its "ambiguous". The compiler is not
able to use Type Inference to figure out the type parameter...

Here is a thread that discusses it:

http://groups.google.com/group/micr...bb32de857b1/cf4e46ca8f99b798#cf4e46ca8f99b798

Personally I find in the case of GetCustomAttribute (as the thread shows) it
makes sense as the type parameter is encapsulating the downcast, plus the
type parameter is used to "do work".



--
Hope this helps
Jay [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


| Hi,
|
| I have a list of different objects in a <List> Structure. There is only
| one category of each kind of object.
|
| Current I have the following methods:
|
| public static Flag GetFlagObj()
| {
| foreach (Thingy s in _Thingies)
| {
| if (s is Flag)
| return (Flag)s;
| }
| return null;
| }
|
| public static Cloth GetFlagObj()
| {
| foreach (Thingy s in _Thingies)
| {
| if (s is Cloth)
| return (Cloth)s;
| }
| return null;
| }
|
| public static BedSprd GetFlagObj()
| {
| foreach (Thingy s in _Thingies)
| {
| if (s is BedSprd)
| return (BedSprd)s;
| }
| return null;
| }
|
|
| Is there a way I could have one generic method that would take as a
| parameter the item I wish returned?
|
| Thank you for your help.
| Al
|
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top