2009-11-29 11 views
5

Tengo una clase genérica y quiero hacer cumplir que las instancias del parámetro de tipo son siempre "cast-able"/convertible desde String. ¿Es posible hacer esto sin, por ejemplo, usar una interfaz?¿Cómo comprobar si existe un molde implícito o explícito?

aplicación posible:

public class MyClass<T> where T : IConvertibleFrom<string>, new() 
{ 
    public T DoSomethingWith(string s) 
    { 
     // ... 
    } 
} 

aplicación ideal:

public class MyClass<T> 
{ 
    public T DoSomethingWith(string s) 
    { 
     // CanBeConvertedFrom would return true if explicit or implicit cast exists 
     if(!typeof(T).CanBeConvertedFrom(typeof(String)) 
     { 
      throw new Exception(); 
     } 
     // ... 
    } 
} 

La razón por la cual yo preferiría esta implementación "ideal" es principalmente con el fin de no forzar todo el Ts para implementar IConvertibleFrom <> .

+2

¿Qué es tan ideal acerca de una implementación que reacciona a los errores de tiempo de programación con excepciones de tiempo de ejecución? –

+1

si tiene un grupo de tipos que ya están convirtiendo desde cadena y desea usarlos en una nueva clase/método en la forma en que lo describí de manera abstracta, esta sería la forma menos difícil de implementarlo. Sería una buena idea editar todo tipo e implementar la nueva interfaz. –

Respuesta

3

Dado que desea convertir desde el tipo Cadena sellada, puede ignorar anulable posible, el boxeo, la referencia y explícito conversiones Solo op_Implicit() califica. Un enfoque más genérico es proporcionada por la clase System.Linq.Expressions.Expression:

using System.Linq.Expressions; 
... 
    public static T DoSomethingWith(string s) 
    { 
     var expr = Expression.Constant(s); 
     var convert = Expression.Convert(expr, typeof(T)); 
     return (T)convert.Method.Invoke(null, new object[] { s }); 
    } 

Cuidado con el costo de reflexión.

+0

¡Esto funciona, gracias! –

-1

¿Por qué no puedes hacer algo como esto?

public class MyClass<T> where T : string 
{ 
    public T DoSomethingWith(string s) 
    { 
     // ... 
    } 
} 

De esta manera se puede comprobar si s es convertible en T en el código DoSomethingWith. Desde allí se puede lanzar una excepción si no puede, o hacer la colada, si puede

+1

¿Por qué usar genéricos en absoluto si declara explícitamente que el tipo genérico tiene que ser una cadena? –

+0

d, declare 'T' como debe derivarse de la cadena, esto no es lo mismo que decir que debe ser una cadena. – Graviton

+1

No, tengo mis propios tipos que se pueden convertir a partir de una cadena. (PD: no puedes heredar de la cadena). –

-1
if(!typeof(T).IsAssignableFrom(typeof(String))) { 
    throw new Exception(); 
} 
+1

Desafortunadamente, no funciona con operadores de conversión implícitos o explícitos declarados en el tipo de argumento. –

+0

hmm, no estoy seguro de que te sigo en tu respuesta. esa pieza de código arrojaría una excepción si 'T' fuera un int, por ejemplo, pero no si era una cadena o un objeto. ¿No es eso lo que buscas? –

+0

Lo probé con la clase MyClass {operador implícito estático público MyClass (string s) {return new MyClass(); }} y typeof (MyClass) .IsAssignableFrom (typeof (string)) devuelve falso. Supongo que esperaba que fuera cierto ... –

Cuestiones relacionadas