2008-08-12 18 views
186

Tengo una clase que quiero usar para almacenar "propiedades" para otra clase. Estas propiedades simplemente tienen un nombre y un valor. Idealmente, lo que me gustaría es poder agregar propiedades mecanografiadas, de modo que el "valor" devuelto sea siempre del tipo que quiero que sea.Conversión de tipo genérico FROM cadena

El tipo siempre debe ser primitivo. Esta clase subclasifica una clase abstracta que básicamente almacena el nombre y el valor como cadena. La idea es que esta subclase agregará cierta seguridad de tipo a la clase base (y me ahorrará alguna conversión).

lo tanto, he creado una clase que es (más o menos) esto:

public class TypedProperty<DataType> : Property 
{ 
    public DataType TypedValue 
    { 
     get { // Having problems here! } 
     set { base.Value = value.ToString();} 
    } 
} 

Entonces la pregunta es:

¿Hay alguna forma "genérica" ​​convertir de cadena de nuevo a una primitiva ?

Me parece que no puede encontrar ninguna interfaz genérica que une la conversión a través del tablero (algo así como ITryParsable hubiera sido ideal!).

+0

Me gustaría ver un ejemplo de su clase concreta, incluso solo un fragmento. :) –

+0

¿puede por favor publicar las partes relevantes de su clase base? – JJS

Respuesta

298

No estoy seguro de haber entendido bien tus intenciones, pero veamos si esta ayuda.

public class TypedProperty<T> : Property where T : IConvertible 
{ 
    public T TypedValue 
    { 
     get { return (T)Convert.ChangeType(base.Value, typeof(T)); } 
     set { base.Value = value.ToString();} 
    } 
} 
+0

Me he estado preguntando por unos días cómo deserializar una secuencia en un tipo genérico. Gracias :) – Trap

+10

Esto solo funciona si tu tipo implementa IConvertible – Kilhoffer

+3

Acepto, aunque 'Convert.ChangeType' no es una solución muy universal y extensible, funciona para la mayoría de los tipos básicos. si se necesita algo mejor, no hay problema para incluir este método en algo más grande como lo sugirió Tim o utilizar un método de conversión diferente. –

3

Posiblemente podría utilizar una construcción como traits class. De esta forma, tendrías una clase de ayuda parametrizada que sabe cómo convertir una cadena en un valor de su propio tipo. Entonces su comprador podría tener este aspecto:

get { return StringConverter<DataType>.FromString(base.Value); } 

Ahora, debo señalar que mi experiencia con tipos parametrizados se limita a C++ y sus plantillas, pero me imagino que hay alguna manera de hacer el mismo tipo de cosas usando C# genéricos.

+0

Las versiones genéricas no existen en C#. – Shimmy

10

Para muchos tipos (entero, doble, DateTime etc), hay un método Parse estática. Puede invocarlo utilizando la reflexión:

MethodInfo m = typeof(T).GetMethod("Parse", new Type[] { typeof(string) }); 

if (m != null) 
{ 
    return m.Invoke(null, new object[] { base.Value }); 
} 
60

lubos El método hasko falla para nullables. El siguiente método funcionará para nulables. Sin embargo, no se me ocurrió. Lo encontré a través de Google: http://web.archive.org/web/20101214042641/http://dogaoztuzun.com/post/C-Generic-Type-Conversion.aspx crédito a "Atún Toksoz"

Uso primera:

TConverter.ChangeType<T>(StringValue); 

La clase está por debajo.

public static class TConverter 
{ 
    public static T ChangeType<T>(object value) 
    { 
     return (T)ChangeType(typeof(T), value); 
    } 

    public static object ChangeType(Type t, object value) 
    { 
     TypeConverter tc = TypeDescriptor.GetConverter(t); 
     return tc.ConvertFrom(value); 
    } 

    public static void RegisterTypeConverter<T, TC>() where TC : TypeConverter 
    { 

     TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(typeof(TC))); 
    } 
} 
+0

Agregaría opciones de conversión de retroceso para Enumerados y otras estructuras complejas, pero es una buena opción. –

+1

¿Por qué RegisterTypeConverter? ¿Necesitamos registrar los convertidores de antemano? (desafortunadamente el enlace está muerto, así que no pude leerlo) – Cohen

+0

Para conversiones múltiples, probablemente debería crear 'tc' (el' TypeConverter') por única vez. 'TypeConverter' es lento porque usa la reflexión para buscar' TypeConverterAttribute'. Si inicializa un solo campo privado 'TypeConverter', entonces podrá volver a utilizar' TypeConverter' muchas veces. –

0
public class TypedProperty<T> : Property 
{ 
    public T TypedValue 
    { 
     get { return (T)(object)base.Value; } 
     set { base.Value = value.ToString();} 
    } 
} 

I usando la conversión a través de un objeto. Es un poco más simple.

+0

agradecimiento que tiene que convertir una T en una interfaz y el simple objeto de conversión T funciona correctamente, fácil y rápido gracias – LXG

+5

(int) (objeto) "54"; es una FATALIDAD !, ¡esto no es VB! –

5
TypeDescriptor.GetConverter(PropertyObject).ConvertFrom(Value) 

TypeDescriptor es la clase que tiene GetConvertor método que aceptan un objeto Type y luego se le puede llamar ConvertFrom método para convertir el value para ese objeto especificado.

+0

Ya respondiste ¿no? – nawfal

0

Utilicé lobos y funciona.Pero tuve un problema con la conversión de dobles debido a la configuración de cultivo. Así que agregué

return (T)Convert.ChangeType(base.Value, typeof(T), CultureInfo.InvariantCulture); 
1

Compruebe la estática Nullable.GetUnderlyingType. - Si el tipo subyacente es nulo, el parámetro de la plantilla no es Nullable, y podemos usar ese tipo directamente - Si el tipo subyacente no es nulo, utilice el tipo subyacente en la conversión.

parece funcionar para mí:

public object Get(string _toparse, Type _t) 
{ 
    // Test for Nullable<T> and return the base type instead: 
    Type undertype = Nullable.GetUnderlyingType(_t); 
    Type basetype = undertype == null ? _t : undertype; 
    return Convert.ChangeType(_toparse, basetype); 
} 

public T Get<T>(string _key) 
{ 
    return (T)Get(_key, typeof(T)); 
} 

public void test() 
{ 
    int x = Get<int>("14"); 
    int? nx = Get<Nullable<int>>("14"); 
} 
0

Aún otra variación. Maneja Nullables, así como situaciones donde la cadena es nula y T es no nullable.

public class TypedProperty<T> : Property where T : IConvertible 
{ 
    public T TypedValue 
    { 
     get 
     { 
      if (base.Value == null) return default(T); 
      var type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T); 
      return (T)Convert.ChangeType(base.Value, type); 
     } 
     set { base.Value = value.ToString(); } 
    } 
} 
Cuestiones relacionadas