无法在泛型方法中将类型更改为可为空

本文关键字:类型 泛型方法 | 更新日期: 2023-09-27 18:32:09

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

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

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<DateTime> 。既然该方法创建并返回可为 null 的类型,为什么强制转换失败?

最后,我想在这个特定示例中有一个可为空的日期时间。

编辑 问题是StringToNullableDatetime方法返回一个Datetime?,并且强制转换说无法从Datetime转换

由于 StringToNullableDatetime 方法返回可为空的日期时间,因此Convert.ChangeType怎么可能看不到传递的参数可为空?

附言。我读过像这样的答案,它们的作用恰恰相反(从可为空转换)。

无法在泛型方法中将类型更改为可为空

抛出的异常说它无法从DateTime转换为Nullable<DateTime>。既然该方法创建并返回可为 null 的类型,为什么强制转换失败?

问得好。这将失败,因为没有盒装可为空的东西。将DateTime?转换为 object 时,如果DateTime?为 null,则获得空引用,或者获得装箱DateTime )。你永远不会得到一个带框的可为空结构;没有这样的事情。

因此,您最终会在该框中使用 null 或有效的日期时间。然后,您告诉转换将其转换为可为空的日期时间,而转换不知道如何做到这一点。

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

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) ...

根据文档,如果出现以下情况,此行将出错:

值为空,转换类型为值类型

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

空值、泛型和拳击交互的方式很奇怪。 最好定义两个方法:

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

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