views:

268

answers:

6

I have a method like the following:

public IEnumerable<T> GetControls<T>()
 : where T : ControlBase
{
 // removed.
}

I then created a class:

public class HandleBase<TOwner> : ControlBase
 : TOwner
{
 // Removed
}

I'd like to be able to call

GetControls<HandleBase<this.GetType()>>; 

where it would use the type of THIS class to pass to the HandleBase. This would in essentially get all HandleBase that have an owner of THIS type.

How can I achieve this?

EDIT:

I'm using .NET 2.0 so solutions greater than 2.0 will not work.

The idea is to have ControlBase have a collection of other ControlBase for "children". Then they can be queried based on their type with GetControls<T>(). This would allow me to, for example, get all HandleBase for a Shape. Then I can take all of these and set Visible=false or do something else with them. Thus I can manipulate children of a specific type for a collection.

HandleBase<TOwner> requires the TOwner since it has a reference to the "owning type". So you can only add anything that extends HandleBase to a Shape. Make sense?

Thanks for all the help!

+2  A: 

You can't. Generics is a compile-time feature. You would need to include the type as a non-generic parameter to the method, and pass it in there.

David M
You could use reflection to do it. But that really seems like overkill for what is described in the problem. I agree with passing the type reference to the function instead.
gbogumil
System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly(); Type t = a.GetType("SeaSharpWinApp8.Program"); MethodInfo mi = t.GetMethod("f", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo miGeneric = mi.MakeGenericMethod(new Type[] { typeof(string)}); miGeneric.Invoke(null, new object[] { "works" });
gbogumil
It's the MakeGenericMethod call that lets you do it. You have to get MethodInfo first, then get another with the specific types you want to use. If it is a generic type then you do the MakeGeneric* call at the type level instead.
gbogumil
- for being able to pass in generics at runtime though, + for suggesting passing type info via method-call
Andreas Niedermair
+12  A: 

You can do this either by specifying a type at compile-time or by using reflection.

You can do it with reflection like this:

typeof(SomeClass).GetMethod("GetControls")
    .MakeGenericMethod(typeof(HandleBase<>).MakeGenericType(GetType()))
    .Invoke(someObject, null);

Note that it would return an object; you would not be able to cast it to IEnumerable<T> (Unless you know what T is at compile-time, in which case there's no point). You would be able to cast it to IEnumerable.

However, this is a bad idea.
There is probably a better solution for you; please provide more detail.

SLaks
is this possible using reflection? **How?**
serhio
This is possible using reflection, by calling `typeof(SomeClass).GetMethod("GetControls").MakeGenericMethod(typeof(HandleBase<>).MakeGenericType(GetType())).Invoke(someObject, null)`
SLaks
Why was this downvoted?
SLaks
@SLaks, see my edit on the original post for more detail. Thanks!
TheCloudlessSky
It looks like you can just write `GetControls<MyType>()` at compile-time, where `MyType` is the class you're writing. If your type might be inherited, you can make it take a generic parameter for the concrete inherited type.
SLaks
+1 for the comment about bad Idea :)
serhio
+1  A: 

Note that type parameters are not variables. Therefore, you cannot use a variable in place of a type parameter.

You could, however, do this through reflection, or by using a special construct which is pretty limited but may solve your case:

public class MyClass<TSelf> where TSelf: MyClass<TSelf> {
    public IEnumerable<T> GetControls<T>() where T: ControlBase {
     // removed.
    }

    public void MyCall() {
        GetControls<HandleBase<TSelf>>(); 
    }
}

public class MyConcreteClass: MyClass<MyConcreteClass> {
}
Lucero
A: 

Probably there is no way to do what you ask for. Extending your example:

X x = GetControls<HandleBase<this.GetType()>>; 

What should the type X be here? However from other background information it seems that you need to get list of all controls of given type. You could do this for example in such way:

public IEnumerable<ControlBase> GetControls(Type type) {
//your logic here
}

Depending on your other usages and goals you might also want to return non-generic IEnumerable.

iPhone beginner
A: 

Since GetControls() returns an enumeration, you might find a way to filter the resulting enumeration with .OfType<T>, something like

List<T2> list = controlList.GetControls<T>().OfType<T2>().ToList();

You would need a generic constraint somehwere along the lines of

where T2 : T
Cylon Cat
That's specific to >= 3.0, I forgot to mention I'm using 2.0.
TheCloudlessSky
A: 

This is specific to my implementation of this but I was able to solve this by creating a non-generic HandleBase first and then a generic HandleBase<TOwner> since the only place TOwner was being used was the property Owner.

Then when I can call GetControls<HandleBase> and get all HandleBase regardless of the Owner.

Thanks all for answers!

TheCloudlessSky