views:

103

answers:

3

I have some fairly simple (at least when you skip error checking, event stuff, et cetera) parameter classes. They are "assembled" kind of like this:

public interface IParameter
{
    Type ValueType { get; }
    object Value { get; set; }
}

public interface IParameter<TValue> : IParameter
{
    new TValue Value { get; set; }
}

public abstract class ParameterBase<TValue> : IParameter<TValue>
{
    public abstract TValue Value { get; set; }
    object IParameter.Value
    {
        get { return Value; }
        set
        {
            if (value is TValue) Value = (TValue)value;
            else throw new ArgumentException("Wrong type.");
        }
    }
    public Type ValueType { get { return typeof(TValue); } }
}

So to for example create an integer based parameter you would create the following class:

public class NumberParameter : ParameterBase<int>
{
    private int number;
    public override int Value { get { return number; } set {number = value; } }
}

My issue is that some of these parameters will have a text representation in the user interface. For example the value type could be a list of integers, but the user should be able to type those integers in to a text box, for example separated by commas.

Where would you put this translation/conversion functionality? And how would you implement it? Is there a smart way to make it neat code-wise?

Currently I have added a public string ValueAsText property to the parameters that needs this conversion, but I kind of feel that it clutters up the parameter class with functionality it strictly shouldn't have to care about. I'm thinking some sort of intermediate class, type converter, formatter + parser, or... something... maybe just talking gibberish here... I have the parameter and the text box. I can create a formatter and a parser for converting the value to and from a string. But how do I connect the dots in a good way?

Anyone understand what I mean? Any clever ideas?


Clarification: I don't want to convert the parameter itself to a string, only display its value as a string and set the value from a string. In other words, the parameter instance itself have to stay the same.


More clarification: In the ui, the parameter is represented by a component that generally consist of a label with the parameter name, a textbox and/or some other input control. For example a date parameter would have a textbox (where you can type in a date range) and a button that opens a date-picker (where you can select a date range). In that case the parameters TValue would for example be IEnumerable<DateTime>, which is all that parameter should really need. But because I also want the user to be able to type that range of dates in as a string in a textbox, I need to convert that string into a sequence of dates somewhere. Currently I have done that by adding a ValueAsText property to the date parameter which does the translating back and forth. The TextBox is then "talks" to the ValueAsText property, and the date picker "talks" to the Value property. This works, but I kind of feel that the parameter classes are doing too much. I think that translating work belongs somewhere in between there. But not sure where and how the hooking up would then work. For example I could have a range parser class that can parse a string into a sequence of dates and a range formatter class that can take a range and create a string out of it. But who would create them and where would they live? I'm thinking step one could be to just create those classes and have them live behind the ValueAsText property. That way most of the functionality is separated out at least. But yeah, I don't really know. I'm looking for ideas and want to learn. That was the reason for this question :)

+1  A: 

I think that the most clean (and standard) way is to just override the ToString method on the class that holds the value for the to string conversion, and to provide Parse and TryParse methods for going the other way around.

Konamiman
+2  A: 

Have you thought of implementing System.ComponentModel.TypeConverter implementations for you NumberParameter type classes, making them first-class citizens in the .NET world like built in types? That way you not only handle conversions to/from string (including for instance support in PropertyGrid controls for editing a 'NumberParameter' without extra work, and I think things like databinding of such values to TextBox.Text and the like) but also possible other type conversions/casts?

peSHIr
Could you give men an example to how what could look? Like if TValue was an IEnumerable<int> for example. (Added a clarification to the question btw)
Svish
See reply by Marc Gravell for examples of what I mean.
peSHIr
+2  A: 

It depends a little bit on your requirements; in general I would use a TypeConverter here - well supported and extensible:

TypeConverter converter = TypeDescriptor.GetConverter(typeof(TValue));
string text = converter.ConvertToString(value);
value = (TValue)converter.ConvertFromString(text);

This handles culture etc (see overloads - use invariant for serialization), and if a type outside your control doesn't have a converter, you can still add one:

TypeDescriptor.AddAttributes(typeof(Person),
    new TypeConverterAttribute(typeof(PersonConverter)));

You can also decorate your own types simply as:

[TypeConverter(typeof(PersonConverter))]
public class Person {...}

One caveat, though; it (TypeDescriptor / System.ComponentModel) isn't on all frameworks; if you need to support CF / Silverlight / etc you should check that it is supported first. Fine on regular .NET, though. I have some serialization code that needs to work on all frameworks, and I couldn't use this for that reason - I use ToString() and static T Parse(string) instead.

Marc Gravell
Hm... so you would add a TypeConverter for, say, IEnumerable<int>? Or how would that work with a sequence of integers?
Svish
(Added a clarification to the question)
Svish
Not sure I get how you would hook this stuff up... =/
Svish