2009-03-28 24 views
25

estoy escribiendo .NET On-the-Fly compilador para scripting CLR y quiere hacer método de ejecución aceptable genérica:operador como y clases genéricas

object Execute() 
{ 
    return type.InvokeMember(..); 
} 

T Execute<T>() 
{ 
    return Execute() as T; /* doesn't work: 
    The type parameter 'T' cannot be used with the 'as' operator because 
    it does not have a class type constraint nor a 'class' constraint */ 

    // also neither typeof(T) not T.GetType(), so on are possible 

    return (T) Execute(); // ok 
} 

Pero creo operador as será muy útil: si el tipo de resultado no es T método ¡devolverá null, en lugar de una excepción! Es posible de hacer?

Respuesta

49

es necesario agregar

where T : class 

a su declaración de método, por ejemplo,

T Execute<T>() where T : class 
{ 

Por cierto, como sugerencia, esa envoltura genérica en realidad no agrega mucho valor. La persona que llama puede escribir:

MyClass c = whatever.Execute() as MyClass; 

O si quieren lanzar en fallar:

MyClass c = (MyClass)whatever.Execute(); 

El método de envoltura genérica se parece a esto:

MyClass c = whatever.Execute<MyClass>(); 

Las tres versiones tienen que especificar exactamente las mismas tres entidades, solo en diferentes órdenes, por lo que ninguna es más simple o más conveniente, y sin embargo la versión genérica oculta lo que está sucediendo, mientras que las versiones "crudas" dejan claro si será un lanzamiento o un null.

(Esto puede ser irrelevante para usted si su ejemplo se simplifica de su código real).

+0

Muchas gracias por su respuesta. Lo usaré, verificaré y marcaré como respuesta. Y, a continuación, uso mi código: MyClass c = compiler.Execute (); Creo que es mejor que MyClass c = compiler.Execute() como MyClass; (Comprobar dentro es mejor que afuera, supongo) – abatishchev

+0

¡Pero el cheque aún se necesita fuera, el cheque de nulo! :) Al hacer que el usuario escriba 'como MyClass', deja más claro que se requiere la verificación de null. –

+0

Hm .. ¡Parece que tienes razón! Recomendaré usar Execute() "normal", pero para el usuario final podría ser útil tener dicho Execute() "anormal", además de "experimento genérico" de alguna manera :) – abatishchev

11

No se puede usar el operador as con un tipo genérico sin restricciones. Como el operador as usa null para representar que no era del tipo, no puede usarlo en tipos de valores. Si desea utilizar obj as T, T, tiene como tipo de referencia.

T Execute<T>() where T : class 
{ 
    return Execute() as T; 
} 
1

parece que se acaba de agregar un método de envoltura para convertir al tipo que el usuario desea, por tanto, sólo se suma a la sobrecarga de ejecución. Para el usuario, la escritura

int result = Execute<int>(); 

no es muy diferente de

int result = (int)Execute(); 

Puede utilizar el cabo modificador para escribir el resultado en una variable en el ámbito de la persona que llama, y ​​devolver una bandera booleana para decir si tuvo éxito:

bool Execute<T>(out T result) where T : class 
{ 
    result = Execute() as T; 
    return result != null; 
} 
1

¿Hay alguna posibilidad de que Execute() devuelva un tipo de valor? Si es así, entonces necesitas el método de Earwicker para los tipos de clases y otro método genérico para los tipos de valores.Podría tener este aspecto:

Nullable<T> ExecuteForValueType<T> where T : struct 

La lógica dentro de ese método dirían

object rawResult = Execute(); 

Entonces, usted tendría que obtener el tipo de rawResult y ver si se puede asignar a T:

Nullable<T> finalReturnValue = null; 

Type theType = rawResult.GetType(); 
Type tType = typeof(T); 

if(tType.IsAssignableFrom(theType)) 
{ 
    finalReturnValue = tType;  
} 

return finalReturnValue; 

Finalmente, haga que su mensaje de ejecución original descubra qué T tiene (clase o tipo de estructura) y llame a la implementación adecuada.

Nota: Esto es de la memoria en bruto. Hice esto hace aproximadamente un año y probablemente no recuerdo todos los detalles. Aún así, espero que apuntarlo en la dirección general ayude.

Cuestiones relacionadas