将泛型类型转换为字符串并返回

时间:2016-11-21 18:19:06

标签: c# generics type-conversion

我想构建一个具有下限和上限的简单泛型Range

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
}

使用DateTime

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

在我的代码中,我现在可以创建一个新的DateTimeRange,并将其传递给我的api-enpoint作为query-parameter

  

HTTP:/.../ API /端点范围= 2016-10-21T18:08:03.6190988Z,2016-11-21T18:08:03.6190988Z

但是如何在api端转换回来呢?在那里我只有字符串2016-10-21T18:08:03.6190988Z,2016-11-21T18:08:03.6190988Z并知道我的控制器 - 动作

中的类型
  

EndpointController.Get(DateTimeRange range){/ *用解析的范围执行某些操作* /}

但不知道如何将其转换回Range<DateTime>

我已经调查了TypeConverter,但没有找到有关仿制药的任何有用信息。

在这里使用类型转换器是正确的方法还是有关于如何实现这一目标的其他最佳实践?

2 个答案:

答案 0 :(得分:2)

您无法在范围类上实现静态方法,无需传递对象即可访问已实现的方法。

这可能符合您的需求:

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
}

然后 DateTimeRange 类:

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

<强>用法:

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

终点方法:

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

很高兴为您服务!

答案 1 :(得分:0)

您可以使用单一类型(但没有自定义格式化程序)执行此操作:

https://dotnetfiddle.net/nXsI2S

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

    private Range()
    {
    }

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

    internal Range(string source)
    {
        string[] parts = source.Split(',');

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

        var tc = TypeDescriptor.GetConverter(typeof(T));

        if(!Range<T>.CanConvert(source))
            throw new ArgumentException("string in invalid format", "source");

        this.Lower = ((T)tc.ConvertFrom(parts[0]));
        this.Upper = ((T)tc.ConvertFrom(parts[1]));
    }

    public static bool CanConvert(string source)
    {
        string[] parts = source.Split(',');

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

        var tc = TypeDescriptor.GetConverter(typeof(T));

        if(!tc.CanConvertFrom(typeof(string)))
           return false;

        return tc.IsValid(parts[0]) && tc.IsValid(parts[1]);
    }

    public static Range<T> Parse(string source)
    {
        Range<T> ret = new Range<T>();

        string[] parts = source.Split(',');

        if(parts.Length <= 1)
            throw new ArgumentException("string in invalid format", "source");

        if(!Range<T>.CanConvert(source))
            throw new ArgumentException("string in invalid format", "source");

        return new Range<T>(source);
    }

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

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

<强>用法:

string range = "2016-10-01T19:38:05.6409410+00:00,2016-11-21T19:38:05.6409410+00:00";

if(Range<int>.CanConvert(range))
    Console.WriteLine(Range<int>.Parse(range).AsString);

if(Range<DateTime>.CanConvert(range))
    Console.WriteLine(Range<DateTime>.Parse(range).AsString);