首页 > 解决方案 > Razor 模板中的 Nullable DateTime 错误

问题描述

更新

所以看起来这在 .NET 4.7.2 中也是可以复制的:

https://dotnetfiddle.net/NI8H1n


原来的

DateTime?在 netcoreapp3.1 中的剃刀模板中遇到了问题。模板正在运行:

Engine.Razor.RunCompile("templateName", "templateKey" model: model);

被传递的模型包含以下属性:

public DateTime? IssueDate { get; set; }

在模板内引发 null ref 错误的剃刀线是:

<td>Issue date: @(result.IssueDate.HasValue ? result.IssueDate.Value.ToString("dd/MM/yyyy") : "")</td>

错误:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform runtime binding on a null reference

所以经过一番调试,我发现如果我把模板里有问题的那行改成:

<td>Issue date: @(result.IssueDate != null? result.IssueDate.ToString("dd/MM/yyyy") : "")</td>

然后我们就可以走了。

所以我的问题是为什么初始线不起作用?

标签: c#.net.net-core

解决方案


由于您的视图 - 从您的 Fiddle 在下面复制 - 不包含@model声明,因此该类型dynamic正在用于视图模型。

@(Model.SomeDate.HasValue ? Model.SomeDate.Value.ToString("dd/MM/yyyy") : "No Value")  

编译后,上面的语句如下所示 - 注意使用dynamic.

public override async Task ExecuteAsync()
{
    this.Write((((dynamic)base.Model).SomeDate.HasValue) 
        ? ((dynamic)base.Model).SomeDate.Value.ToString("dd/MM/yyyy") 
        : "No Value"
        );
}

考虑文档中的信息dynamic

  1. dynamic 类型的变量被编译成 object 类型的变量。因此,动态类型只存在于编译时,而不是运行时。
  2. 任何非空表达式都可以转换为动态类型

这使得该类型dynamic必须在运行时评估其操作和数据类型。


public class SampleViewModel
{
    public DateTime? SomeDate {get;set;}
}

鉴于您在上面的模型, whereSomeDate的类型为Nullable<DateTime>.

当该SomeDate属性具有 valuenull时,您会得到Cannot perform runtime binding on a null reference异常,因为代码尝试访问.HasValuea null,而不是访问可能已转换为 a 的东西dynamic(要点 2)。

当它SomeDate具有DateTime.NowFiddle 中所示的值时,动态运行时绑定得出结论,它SomeDate必须是类型System.DateTime,因为DateTime.Now它不可为空,并且只有非空表达式可以转换为dynamic类型(要点 2)。
因此,您会得到'System.DateTime' does not contain a definition for 'HasValue'异常,因为 aDateTime不包含HasValue属性。


使HasValue检查工作的一种方法是在视图中包含模型声明,因为它避免了必须使用类型dynamic- 请参阅更新的 Fiddle

@model HelloWorldMvcApp.SampleViewModel
@(Model.SomeDate.HasValue ? Model.SomeDate.Value.ToString("dd/MM/yyyy") : "No Value")

推荐阅读