2010-04-09 10 views
9

que tienen un método como el siguiente:C# Pass genéricos en tiempo de ejecución

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

que luego creó una clase:

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

me gustaría ser capaz de llamar

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

donde usaría el tipo de ESTA clase para pasar al HandleBase. Esto esencialmente obtendría todos los HandleBase que tienen un propietario de ESTE tipo.

¿Cómo puedo lograrlo?

EDIT:

estoy usando .NET 2.0 por lo que las soluciones superiores a 2.0 no funcionarán.

La idea es que ControlBase tenga una colección de otras ControlBase para "niños". Luego se pueden consultar según su tipo con GetControls<T>(). Esto me permitiría, por ejemplo, obtener todos los HandleBase para una forma. Entonces puedo tomar todo esto y establecer Visible = falso o hacer algo más con ellos. Por lo tanto, puedo manipular a niños de un tipo específico para una colección.

requiere que TOwner tenga referencia al "tipo propietario". Por lo tanto, solo puede agregar cualquier elemento que extienda HandleBase a Shape. ¿Tener sentido?

¡Gracias por toda la ayuda!

+2

@TheCloudlessSky, ¿por qué invocar 'this.GetType()'? si está invocando 'GetControls >();' desde una clase basada en instancia [como 'this' indica], ¿por qué no simplemente usar el nombre de tipo declarado de la clase implementadora? si esta es una clase base, hay medios para exponer el tipo de la subclase a la clase base. –

+0

Ver la edición anterior. – TheCloudlessSky

Respuesta

0

esto es específico para mi implementación de esto, pero yo era capaz de resolver esto mediante la creación de un no genérico HandleBase primero y luego un genérico HandleBase<TOwner> ya que el único lugar TOwner estaba siendo usado como propietario de la propiedad.

Luego, cuando puedo llamar al GetControls<HandleBase> y obtener todos los HandleBase independientemente del propietario.

¡Gracias a todos por las respuestas!

2

No puede. Generics es una característica en tiempo de compilación. Debería incluir el tipo como un parámetro no genérico en el método y pasarlo allí.

+1

Podría usar el reflejo para hacerlo. Pero eso realmente parece excesivo para lo que se describe en el problema. Estoy de acuerdo con pasar la referencia de tipo a la función en su lugar. –

+0

System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly(); Tipo 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, nuevo objeto [] {"funciona"}); –

+0

Es la llamada MakeGenericMethod que te permite hacerlo. Primero debe obtener MethodInfo y luego obtener otro con los tipos específicos que desea usar. Si es un tipo genérico, entonces realiza la llamada MakeGeneric * en el nivel de tipo. –

13

Puede hacer esto especificando un tipo en tiempo de compilación o mediante el reflejo.

Puede hacerlo con la reflexión de esta manera:

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

Nota que volvería una object; no podría convertirlo al IEnumerable<T> (a menos que sepa lo que T está en tiempo de compilación, en cuyo caso no tiene sentido). Podrías lanzarlo al IEnumerable.

Sin embargo, esta es una mala idea.
Probablemente haya una mejor solución para usted; por favor proporciona más detalles.

+0

¿es esto posible usando la reflexión? ** ¿Cómo? ** – serhio

+3

Esto es posible mediante la reflexión, al invocar 'typeof (SomeClass) .GetMethod (" GetControls "). MakeGenericMethod (typeof (HandleBase <>). MakeGenericType (GetType())). Invoke (someObject, null) ' – SLaks

+0

¿Por qué se bajó este valor? – SLaks

1

Tenga en cuenta que los parámetros de tipo no son variables. Por lo tanto, no puede usar una variable en lugar de un parámetro de tipo.

Se podría, sin embargo, hacer esto a través de la reflexión, o mediante el uso de una construcción especial que es bastante limitado, pero puede resolver su caso:

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> { 
} 
0

Probablemente no hay manera de hacer lo que pide. Extendiendo su ejemplo:

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

¿Cuál debe ser el tipo X aquí? Sin embargo, a partir de otra información básica, parece que necesita obtener una lista de todos los controles del tipo dado.Usted puede hacer esto, por ejemplo, de tal manera:

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

Dependiendo de sus otros usos y objetivos también puede que quiera volver no genérico IEnumerable.

0

Desde GetControls() devuelve una enumeración, es posible encontrar una forma de filtrar la enumeración resultante con .OfType <T>, algo así como

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

Se necesitaría una limitación genérica somehwere lo largo de las líneas de

where T2 : T 
+0

Eso es específico de> = 3.0, olvidé mencionar que estoy usando 2.0. – TheCloudlessSky

Cuestiones relacionadas