Question

I have a class that I want to use to store "properties" for another class. These properties simply have a name and a value. Ideally, what I would like is to be able to add typed properties, so that the "value" returned is always of the type that I want it to be.

The type should always be a primitive. This class subclasses an abstract class which basically stores the name and value as string. The idea being that this subclass will add some type-safety to the base class (as well as saving me on some conversion).

So, I have created a class which is (roughly) this:

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

So the question is:

Is there a "generic" way to convert from string back to a primitive?

I can't seem to find any generic interface that links the conversion across the board (something like ITryParsable would have been ideal!).

Was it helpful?

Solution

I am not sure whether I understood your intentions correctly, but let's see if this one helps.

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

OTHER TIPS

lubos hasko's method fails for nullables. The method below will work for nullables. I didn't come up with it, though. I found it via Google: http://web.archive.org/web/20101214042641/http://dogaoztuzun.com/post/C-Generic-Type-Conversion.aspx Credit to "Tuna Toksoz"

Usage first:

TConverter.ChangeType<T>(StringValue);  

The class is below.

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

For many types (integer, double, DateTime etc), there is a static Parse method. You can invoke it using reflection:

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 is class having method GetConvertor which accept a Type object and then you can call ConvertFrom method to convert the value for that specified object.

You could possibly use a construct such as a traits class. In this way, you would have a parameterised helper class that knows how to convert a string to a value of its own type. Then your getter might look like this:

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

Now, I must point out that my experience with parameterised types is limited to C++ and its templates, but I imagine there is some way to do the same sort of thing using C# generics.

Check the static Nullable.GetUnderlyingType. - If the underlying type is null, then the template parameter is not Nullable, and we can use that type directly - If the underlying type is not null, then use the underlying type in the conversion.

Seems to work for me:

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

I using converting via an object. It is a little bit simpler.

I used lobos answer and it works. But I had a problem with the conversion of doubles because of the culture settings. So I added

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

Yet another variation. Handles Nullables, as well as situations where the string is null and T is not 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(); }
    }
}

With inspiration from the Bob's answer, these extensions also support null value conversion and all primitive conversion back and fourth.

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

Examples

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

            int? intValue = null;
            var strResult = intValue.Convert<string>();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top