2016-11-21 172 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

這看起來更接近你所需要的東西。 –