KingKerosin KingKerosin - 14 days ago 4
C# Question

Convert generic type to string and back

I want to build a simple generic

Range
that has a lower and a upper bound.

public abstract class Range<T>
{
Range(T lower, T upper){/* init _lowerValue and _upperValue (both of type T) */}

// this method I would use inside TypeConverter...
public static Range<T> Parse(string source){/* build a new instance from string, but how? */}

public LowerString => ValueToString(_lowerValue);
public UpperString => ValueToString(_upperValue);

public abstract string ValueToString(T value); // must be overridden
public abstract T StringToValue(string source); // must be overridden

public string AsString => $"{LowerString},{UpperString}"; // gets the string-representation of the object
}


With an example implementation for
DateTime


public class DateTimeRange : Range<DateTime>
{
public override string ValueToString(DateTime value) => value.ToString("O");
public override DateTime StringToValue(string source) => DateTime.Parse(source);
}


In my code I can now create a new DateTimeRange an pass it to my api-enpoint as query-parameter


http:/.../api/EndPoint?range=2016-10-21T18:08:03.6190988Z,2016-11-21T18:08:03.6190988Z


But how can I convert this back on api-side? There I only have the string
2016-10-21T18:08:03.6190988Z,2016-11-21T18:08:03.6190988Z
and know the type in my contoller-action


EndpointController.Get(DateTimeRange range){/* do something with the parsed range */}


but no idea how to convert this back to
Range<DateTime>
.

I've already looked into
TypeConverter
but don't find anything useful about generics there.

Is using type-converter here the correct way to go or are there any other best-practices on how this can be achieved?

Answer

You cannot implement an static method on Range class accessing your implemented method without passing the object.

This could be fit to your needs:

https://dotnetfiddle.net/l2nOSp

public abstract class Range<T> 
{
    internal T Lower { get; set; }
    internal T Upper { get; set; }

    internal Range(T lower, T upper)
    {
        Lower = lower;
        Upper = upper;
    }

    // this method I would use inside TypeConverter...
    internal Range(string source)
    {
        string[] parts = source.Split(',');

        if(parts.Length <= 1)
            throw new ArgumentException();

        if(!this.CanConvert(parts[0]) || !this.CanConvert(parts[1]))
            throw new ArgumentException();

        this.Lower = this.StringToValue(parts[0]);
        this.Upper = this.StringToValue(parts[1]);
    }

    public string LowerString { get { return ValueToString(Lower); } }
    public string UpperString { get { return ValueToString(Upper); } }

    public abstract string ValueToString(T value); // must be overridden
    public abstract T StringToValue(string source); // must be overridden
    internal abstract bool CanConvert(string source); // must be overridden

    public string AsString { get { return string.Format("{0},{1}", LowerString, UpperString); }}// gets the string-representation of the object
}

And then DateTimeRange Class:

public class DateTimeRange : Range<DateTime>
{

    public DateTimeRange(string source) : base(source)
    {

    }

    public DateTimeRange(DateTime lower, DateTime upper):base(lower, upper)
    {

    }

    public override string ValueToString(DateTime value) { return value.ToString("O"); }
    public override DateTime StringToValue(string source) { return DateTime.Parse(source); }
    internal override bool CanConvert(string source) { DateTime dt = new DateTime(); return DateTime.TryParse(source, out dt); }
}

Usage:

Range<DateTime> a = new DateTimeRange(DateTime.Now.AddDays(-20), DateTime.Now);
Console.WriteLine(a.AsString);

Range<DateTime> b = new DateTimeRange("2016-11-01T19:38:05.6409410+00:00,2016-11-21T19:38:05.6409410+00:00");
Console.WriteLine(b.AsString);

Endpoint Method:

public void Get(string range) //EndpointController.Get
{
    Range<DateTime> b = new DateTimeRange(range);
    //Do what you need with properties:
    //b.LowerString
    //b.UpperString
}

Happy to help you!

Comments