views:

3519

answers:

8

Hi Guys,

Here is the problem I am having, 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!).


Update:

@lubos hasko - You understood very well! Your code seems to work like a charm. I can access both the base .Value property (which returns the string) and the subclasses .TypedValue property which always returns the type specified in DataType - Very many thanks, answer accepted!

@Jon Limjap - Thanks for the suggestion, while this would have worked, the problem is that you would still lose the "hard" type of it (i.e. bool, int, whatever) since the return type would become IConvertibleFromString which sadly won't tie in with my original goal.

@dbkk - I have not tried your solution since lubos' worked so well, however I did have concerns about the speed of it (due to reflection) although I am not sure on the actual impact of it. Thank you for the input though.

+2  A: 

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.

Greg Hewgill
+15  A: 

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

public class TypedProperty<T> : Property
{
 public T TypedValue
 {
   get { return (T)Convert.ChangeType(base.Value, typeof(T)); }
   set { base.Value = value.ToString();}
 }
}
lubos hasko
I've been wondering for a few days how to deserialize a stream into a generic type. Thanks :)
Trap
This only works if your type implements IConvertible
Kilhoffer
I agree, although `Convert.ChangeType` is not very universal and extensible solution, it works for most basic types. if something better is needed, it's no problem to wrap this method into something bigger like Tim suggested or use different conversion method altogether.
lubos hasko
A: 

Well, simple answer is no. :(

One thing you could do is have your datatypes as some sort of wrapper of a primitive and follow an interface named, say IConvertibleFromString.

The interface would look something like:

public interface IConvertibleFromString
{
    IConvertibleFromString ConvertFromString(string s);
}

so in your property you could do something like

get { return this.ConvertFromString(base.Value); }

What I do want to know is why store everything in string?

Jon Limjap
A: 

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 }); }
dbkk
A: 

Wow, lots of great answers, thank you to you all! I will work my way through the proposed solutions and see how they get on!

@Jon Limjap, @lubos hasko - I have TBH, I am not sure if this is really the best way for me to do this.. Thinking about it, the benefit I have from typing the property here will probly be outweighed during inspection of the properties later. Jon, I opted for string since it's the lowest common denominator (everything can be represented as a string easily).

@Greg Hewgill, Thanks for the link. As you say, not sure as to how to implement for C# (there probably is a way) but the link does look real useful (straight into delicious!) +1 for sharing, thank you.

Rob Cooper
A: 

I'd be interested in seeing an example of your concrete class, even just a snippet. :)

Jon Limjap
A: 

This does not work in silverlight because not all the functions are in the CLR. you can find more information here

http://www.silverenlightenment.com/

+2  A: 

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://www.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)));
    }
}
Tim Coker