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

C# 将泛型类型转换为字符串并返回,c#,generics,type-conversion,C#,Generics,Type Conversion,我想建立一个简单的通用范围,它有一个下限和一个上限 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(stri

我想建立一个简单的通用范围,它有一个下限和一个上限

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
}
在我的代码中,我现在可以创建一个新的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.GetDateTimeRange范围{/*对解析的范围*/}

但不知道如何将其转换回范围

我已经研究了TypeConverter,但没有发现任何关于泛型的有用信息


在这里使用类型转换器是正确的方法吗?或者在如何实现这一点上还有其他最佳实践吗?

如果不传递对象,就无法在访问已实现方法的范围类上实现静态方法

这可能适合您的需要:

然后是DateTimeRange类:

用法:

端点方法:


很高兴帮助你

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

用法:


为什么不在DatTimeRange上创建一个带字符串的构造函数呢?您想如何使用这些类?发布一个示例…然后我需要为Range的每个新实现创建一个TypeCoverter,或者更改现有的一个,否?您有两个值作为一个范围,并且希望转换为单个值??。。如何选择小写字符串还是大写字符串?@IgorQuirino是的,主要是我想要的。谢谢。两件事。这里的虚拟成员调用构造函数是否正常?第二个:因此,对于每个新的范围实现,我确实需要一个新的TypeConverter,不是吗?。我希望/寻找一些东西,可以帮助我在转换回时的一般斗争…如何知道转换的目标类型?我认为.NET正在寻找一个类型转换器,而实际使用的参数是类型x。因此,对于GetDateTimeRange范围,范围的类型由ModelBuilder/TypeConverter知道。我实际上就是这么做的。我想到了比每次用字符串调用ctor更简单的方法。最后我写了一篇关于类型转换器的文章。但是我每个实现有一个类型转换器。所以你的解决方案很好。也许是我对魔法的期望太高了。这看起来更接近你的需要。
public class DateTimeRange : Range<DateTime>
{
    public override string ValueToString(DateTime value) => value.ToString("O");
    public override DateTime StringToValue(string source) => DateTime.Parse(source);
}
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
}
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
}
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);