【问题标题】:Cannot change type to nullable in generic method无法在泛型方法中将类型更改为可为空
【发布时间】:2012-05-06 07:05:11
【问题描述】:

我正在创建一个通用转换器

这是通用转换器的示例代码

bool TryReaderParse<TType>(object data, out TType value)
{
    value = default(TType);
    Type returnType = typeof(TType);
    object tmpValue = null;

    if (returnType == typeof(DateTime))
    {
        tmpValue = StringToDatetime(data.ToString());
    }
    else if (returnType == typeof(DateTime?)) // THIS IF FIRES
    {
        tmpValue = StringToNullableDatetime(data.ToString());
    }

    value = (TType)Convert.ChangeType(tmpValue, returnType);  // THROWS
}

public DateTime? StringToNullableDatetime(string date)
{
    DateTime? datetime = null;
    if (!string.IsNullOrEmpty(date))
    {
        datetime = DateTime.Parse(date, new CultureInfo(Resources.CurrentCulture));
    }

    return datetime;
}

这就是我使用它的方式:

void foo()
{
    DateTime? date = null;
    TryReaderParse<DateTime?>("25/12/2012", out date);
}

抛出的异常表示它无法从DateTime 转换为Nullable&lt;DateTime&gt;。既然该方法创建并返回一个可为空的类型,那么为什么转换失败了?

最后,在这个特定的示例中,我希望有一个可为空的 DateTime。

edit 问题是StringToNullableDatetime 方法返回一个Datetime? 并且强制转换说不能从Datetime 转换

既然StringToNullableDatetime方法返回一个可以为空的日期时间,那Convert.ChangeType怎么可能看不到传递的参数可以为空呢?

附言。我读过类似this 的答案,相反的答案(从可空值转换)。

【问题讨论】:

    标签: c# generics .net-3.5 casting nullable


    【解决方案1】:

    抛出的异常表示它无法从DateTime 转换为Nullable&lt;DateTime&gt;。既然方法创建并返回了一个可以为空的类型,那么为什么转换会失败呢?

    好问题。这失败了,因为不存在盒装可为空的东西。当您将DateTime? 转换为object 时,如果DateTime? 为空,您将获得一个空引用,或者您将获得一个装箱的,即DateTime。你永远不会得到一个盒装的可为空结构;没有这样的东西。

    因此,您最终会在该框中得到 null 或有效的 DateTime。然后,您告诉 Convert 将其转换为可为空的 DateTime,而 Convert 不知道该怎么做。

    我的建议是你完全放弃这条攻击线;这段代码是对泛型的滥用。每当您切换特定类型的泛型时,您的代码就不再是 generic 并且您可能做错了。如果你想为日期时间做一个“尝试”风格的方法,那么只需写下:

    DateTime? TryReadDateTime(object data)
    {
        ... return null if the object cannot be read as a datetime ...
    }
    

    为您打算阅读的每个类型编写这样的方法。用户更愿意写:

    DateTime? d = TryReadDateTime(data);
    if (d != null) ...
    

    DateTime d;
    bool b = TryRead<DateTime>(data, out d);
    if (b) ...
    

    【讨论】:

      【解决方案2】:

      来自documentation,如果出现以下情况,此行将出错:

      value 为 null,conversionType 为值类型

      Nullable&lt;T&gt; 是一个结构体,因此是一个值类型,因此如果您的值为 null,则不能使用此方法调用。您已经单独处理日期,那么为什么还要在这些情况下使用ChangeType

      【讨论】:

      • 编辑了我的问题。我的问题是我无法返回 Nullable 日期时间。 Convert.ChangeType 行看不到传递的参数可以为空
      【解决方案3】:

      可空值、泛型和装箱的交互方式很奇怪。您最好定义两种方法:

      bool TryReaderParse(object data, out TType value); bool TryReaderParse(object data, out TType? value) where TType : struct;

      在第二种方法中,您的代码可以简单地生成TType 并将其分配给TType? 毫无困难。

      【讨论】:

      • 首先,一个方法不能仅在约束上重载。其次,如果该方法返回一个可为空的值,那么为什么它还需要返回一个布尔值?如果您要这样做,那么正确的签名是T TryParseClass&lt;T&gt;(object data) where T : classT? TryParseStruct&lt;T&gt;(object data) where T : struct。不需要布尔值。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多