【问题标题】:TypeConverter DateTime Format issueTypeConverter DateTime 格式问题
【发布时间】:2013-07-02 07:56:14
【问题描述】:

我正在使用 4.0,并试图通过开发一些用于类型转换的辅助方法来简化我的生活。以下方法运行良好。它将从任何字符串转换为其他数据类型。

System.ComponentModel;

public static T Convert<T>(string s)
{
      var typeConverter = TypeDescriptor.GetConverter(typeof(T));
      if (typeConverter != null && typeConverter.CanConvertFrom(typeof(string)))
      {
          return (T)typeConverter.ConvertFrom(s);
      }
      return default(T);
}

//calling this method...
var dateTime = MyConverter.Convert<DateTime>("13/07/2013");   // Date format "DD/mm/yyyy" 
// Working as expected... Taking "13" as Day, "07" as month

现在以下方法也在同一个类 MyConverter 中,但它不适用于 DateTime:

public static bool CanConvertTo<T>(string s)
{
     var typeConverter = TypeDescriptor.GetConverter(typeof(T));

     if (typeConverter != null && typeConverter.CanConvertFrom(typeof(string)))
     {
         return typeConverter.IsValid(s);
     }
     else
         return false;
}

这个方法的问题是,它只接受 dateformat : "MM/dd/yyyy"

// This will give exception. It is taking "13" as month, "07" as Day
bool canConvert = MyConverter.CanConvertTo<DateTime>("13/07/2013");

编辑 根据 KeyboardP 的建议,我将方法更改为:

public static bool CanConvertTo<T>(string s)
{
    TypeConverter typeConverter;
    if (typeof(T) == typeof(DateTime))
    {
         typeConverter = new DateTimeConverter();
    }
    else
    {
        typeConverter = TypeDescriptor.GetConverter(typeof(T));
    }

    if (typeConverter != null && typeConverter.CanConvertFrom(typeof(string)))
    {
        return typeConverter.IsValid(s);
    }
    else
        return false;
}

并经过测试。测试结果是:

var date = MyConverter.Convert<DateTime>("13/07/2013");    //return perfect date
var canConvert = MyConverter.CanConvertTo<DateTime>("13/07/2013");  // returned false...

所以DateTimeConverter没有成功

【问题讨论】:

  • 听起来像是美国和欧洲日期之间的文化差异。试试 2013 年 13 月 13 日,看看是否会破坏它。
  • 如果是文化差异,那么为什么一种方法有效而另一种方法无效?
  • 如果你传入一个日期格式更明确的值——“2013 年 6 月 13 日”,会发生什么?我想这两种方法都适用。
  • GetCoverter(typeof(DateTime)) 将返回一个DateTimeConverter,因此不需要检查。我是说如果要指定格式,则需要采用可选参数。但是,您关于为什么 IsValid 返回 false,但解析为 true 的问题是一个很好的问题。

标签: c# asp.net .net datetime type-conversion


【解决方案1】:

由于DateTime 可以有许多不同的格式样式,我只使用DateTimeConverter 而不是尝试在通用方法中重新创建它。

编辑

我做了一些 ILspying,这就是我得出的结论(很高兴在任何一点上得到纠正)。

GetCoverter(typeof(DateTime)) 会返回一个DateTimeConverter,所以调用CanConvertFrom 实际上就是调用DateTimeConverter.CanConvertFromCanConvertFrom 调用 base.CanConvertFrombase 是父 TypeConverter 类)。

base.CanConvertFrom 方法如下所示

public virtual bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
    return sourceType == typeof(InstanceDescriptor);
}

由于DateTime.GetType() != typeof(InstanceDescriptor),返回值为falseCanConvertFromIsValid 方法调用,由于我们刚刚建立了返回值为falseIsValid 返回false

那么即使调用了相同的CanConvertFrom 方法,Convert 方法是如何工作的?

嗯,您传递的参数是string 类型,而不是DateTime

typeConverter.CanConvertFrom(typeof(string))

在上面的第一个代码 sn-p 中,CanConvertFrom 方法用于TypeConverter 基类。如果我们查看DateTimeConverter.CanConvertFrom 覆盖,它看起来像这样

public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
    return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}

由于我们将String 作为类型传递,因此该方法返回true(与IsValid 调用不同)。因为这返回true,所以代码继续调用

return (T)typeConverter.ConvertFrom(s);

(其中 T 是 DateTime

DateTimeConverter 只是调用DateTime.Parse 并忽略文化。我不确定这是设计使然还是错误,但我不会依赖DateTime.Parse,除非您知道字符串始终具有相同的格式(或者在调用您的方法之前正确格式化)。

【讨论】:

  • 嗯,我正在尝试开发可用于包括日期时间在内的所有数据类型的东西。 DateTimeConverter 仅用于日期时间。
  • 我理解,但是因为DateTime 比您尝试转换的其他格式复杂得多,所以您只是在重新发明轮子。如果你真的想这样做,那么你的方法可以检查T 是否是DateTime 对象,然后自己调用DateTimeConverter。无论哪种方式,您的方法都必须开始接受可选参数,以便您可以指定 DateTime 字符串格式。
  • 我正在关注您所说的,但这不仅仅是为了解决问题。在同一台机器上,相同的文化配置,相同的类“TypeDescriptor”,相同的日期“13/07/2013”​​,一种方法有效,一种无效。这是我眼中的一个错误。
  • 我已经更新了我的答案。这不是关于如何解决它的直接答案,但我认为它解释了为什么你会得到两个不同的结果。
  • 哦,信息量很大。非常感谢您的所有努力:)
【解决方案2】:

DateTimeConverter.IsValid 不使用当前文化。这是我解决这个问题的方法

public class FixedDateTimeConverter : DateTimeConverter
{
    public override bool IsValid(ITypeDescriptorContext context, object value)
    {
        DateTime d;
        return DateTime.TryParse(value.ToString(), out d);
    }
}

...

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

if (typeof (T) == typeof (DateTime))
    converter = new FixedDateTimeConverter(); 

return converter.IsValid(null,r);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-22
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 2018-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多