2016-11-21 114 views
-1

我想构建一个具有较低和较高界限的简单泛型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作为查询参数

HTTP: /.../api/EndPoint?range=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<DateTime>

我已经看过TypeConverter,但没有发现任何有用的泛型在那里。

在这里使用类型转换器正确的方式去或有任何其他的最佳做法如何实现这一点?

+1

为什么不只是创建'DatTimeRange构造'需要一个'字符串'? – juharr

+0

你想如何使用这个类?发表一个例子... –

+1

然后,我需要为Range 的每个新实现创建一个TypeCoverter,或更改现有的一个,不是? – KingKerosin

回答

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

谢谢。两件事情。构造函数中的虚拟成员调用是否可以在这里? 第二个:因此,我还需要为每个新的Range-implementation实现一个新的TypeConverter,否?我希望/寻找一些可以帮助我转换回... ...的通用奋斗的东西... – KingKerosin

+0

如何知道目标类型的转换? –

+0

如果你不知道期望什么,你的系统可能有多普遍? –

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

这看起来更接近你所需要的东西。 –

相关问题