Pregunta

Tengo una clase que quiero usar para almacenar "propiedades" de otra clase.Estas propiedades simplemente tienen un nombre y un valor.Idealmente lo que me gustaría es poder agregar mecanografiado propiedades, de modo que el "valor" devuelto sea siempre del tipo que quiero que sea.

El tipo siempre debe ser primitivo.Esta clase subclasifica una clase abstracta que básicamente almacena el nombre y el valor como una cadena.La idea es que esta subclase agregará algo de seguridad de tipos a la clase base (además de ahorrarme algunas conversiones).

Entonces, he creado una clase que es (más o menos) esta:

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

Entonces la pregunta es:

¿Existe una forma "genérica" ​​de convertir una cadena a una primitiva?

Parece que no puedo encontrar ninguna interfaz genérica que vincule la conversión en todos los ámbitos (algo como ITryParsable hubiera sido ideal!).

¿Fue útil?

Solución

No estoy seguro de haber entendido correctamente tus intenciones, pero veamos si esto 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();}
    }
}

Otros consejos

El método de lubos hasko falla con valores anulables.El siguiente método funcionará para valores anulables.Aunque no se me ocurrió a mí.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 "Tuna Toksoz"

Uso primero:

TConverter.ChangeType<T>(StringValue);  

La clase está abajo.

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)));
    }
}

Para muchos tipos (entero, doble, DateTime, etc.), existe un método Parse estático.Puedes invocarlo usando la reflexión:

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

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

TypeDescriptor ¿La clase tiene método? GetConvertor que aceptan un Type objeto y luego puedes llamar ConvertFrom método para convertir el value para ese objeto especificado.

Posiblemente podrías usar una construcción como clase de rasgos.De esta manera, tendría una clase auxiliar parametrizada que sabe cómo convertir una cadena en un valor de su propio tipo.Entonces tu captador podría verse así:

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 imagino que hay alguna manera de hacer el mismo tipo de cosas usando genéricos de C#.

comprobar la estática Nullable.GetUnderlyingType.- Si el tipo subyacente es nulo, entonces el parámetro de plantilla no lo es Nullable, y podemos usar ese tipo directamente: si el tipo subyacente no es nulo, entonces use el tipo subyacente en la conversión.

Parece funcionar para mi:

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");
}
public class TypedProperty<T> : Property
{
    public T TypedValue
    {
        get { return (T)(object)base.Value; }
        set { base.Value = value.ToString();}
    }
}

Utilizo la conversión a través de un objeto.Es un poquito más sencillo.

Usé la respuesta de lobos y funciona.Pero tuve un problema con la conversión de dobles debido a los entornos culturales.Entonces agregué

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

Otra variación más.Maneja valores nulos, así como situaciones en las que la cadena es nula y T es no anulable.

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(); }
    }
}

Con inspiración de la BetoLa respuesta de, estas extensiones también admiten la conversión de valores nulos y todas las conversiones primitivas hacia atrás y hacia el cuarto.

public static class ConversionExtensions
{
        public static object Convert(this object value, Type t)
        {
            Type underlyingType = Nullable.GetUnderlyingType(t);

            if (underlyingType != null && value == null)
            {
                return null;
            }
            Type basetype = underlyingType == null ? t : underlyingType;
            return System.Convert.ChangeType(value, basetype);
        }

        public static T Convert<T>(this object value)
        {
            return (T)value.Convert(typeof(T));
        }
}

Ejemplos

            string stringValue = null;
            int? intResult = stringValue.Convert<int?>();

            int? intValue = null;
            var strResult = intValue.Convert<string>();
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top