如何自定义将列表强制转换为其他类型?

时间:2019-09-16 16:04:23

标签: c# .net-core entity-framework-core

使用Entity Framework和Razor页面,我目前有一个系统,可以将我的模型包装到视图模型中并显示在屏幕上,我认为这是我在MVVM中要做的建筑。

但是,我在将类型'Foo'的列表强制转换为'FooView'时遇到了一些麻烦,但是将类型'Foo'的变量强制转换为'FooView'很好。这是代码:

学生班

public class Student
{
    public Student()
    {
        Id = null;
        FirstName = "";
        Surname = "";
        Age = 0;
        DateOfBirth = new DateTime();
        Results = new HashSet<Result>();
    }

    public Student(string firstName, string surname, DateTime dateOfBirth)
    {
        Id = null;
        FirstName = firstName;
        Surname = surname;
        DateOfBirth = dateOfBirth;
        Results = new HashSet<Result>();
    }

    public int? Id { get; set; }

    public string FirstName { get; set; }

    public string Surname { get; set; }

    public int Age { get; private set; }

    // Implement backing field
    private DateTime _dateOfBirth;
    public DateTime DateOfBirth
    {
        get => _dateOfBirth;

        set
        {
            // Set Age when date of birth is provided
            _dateOfBirth = value;
            Age = (DateTime.Today.Year - this._dateOfBirth.Year);
            if (_dateOfBirth.Date > DateTime.Today.AddYears(-this.Age)) this.Age--;
        }
    }

    public HashSet<Result> Results { get; set; }

    public static implicit operator StudentView(Student student)
    {
        return new StudentView(student);
    }

}

成功将学生项目投射到剃须刀页面WORKS上的学生查看项目

@foreach (var item in Model.Result)
{
    <tr>
        <td>
            @Html.DisplayFor(modelItem => ((StudentView)item.Student).FullName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Score)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Grade)
        </td>
        <td>
            <a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
            <a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
            <a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
        </td>
    </tr>
}

尝试投射列表以键入“学生视图”失败

public async Task OnGetAsync()
{
    Student = await _context.Student.Cast<StudentView>().ToListAsync();
}
  

InvalidCastException:无法转换类型的对象    键入“ StudentManagerDemoCore.Models.Student”    'StudentManagerDemoCore.ViewModels.StudentView'。

     

StudentManagerDemoCore.Pages.Teacher.ManageStudent.IndexModel.OnGetAsync()   在Index.cshtml.cs

Student = await _context.Student.Cast<StudentView>().ToListAsync();

我感觉这里缺少一些东西,但是我不确定是什么。该错误表明我的投射方法存在问题,但这并不能解释为什么有时会起作用。

有人知道我要去哪里吗?

3 个答案:

答案 0 :(得分:3)

您可以通过多种方法来解决问题。

第一个解决方案是手动执行以下操作:

await _context.Student.Select(student => new StudentView()
{
    Id = student.Id,
    //....
}

另一种解决方案是拥有一个手动映射器来执行映射。静态函数,它使用Student并将其转换为StudentView并返回它。您可以在其他地方重用它。

我建议的最佳解决方案是使用AutoMapper

答案 1 :(得分:1)

摘自MSDN(我的重点):

  

此方法的源序列是IEnumerable,这意味着元素具有对象的编译时静态类型。 此方法执行的唯一类型转换是引用转换和拆箱转换。集合中元素的运行时类型必须与目标类型匹配,或者在值类型的情况下,元素的运行时类型必须是目标类型的装箱转换的结果。不允许使用其他转换类型,例如不同数字类型之间的转换。

因此,对于您的特定情况,在StudentStudentView之间定义隐式转换时,请执行以下操作:

public async Task OnGetAsync()
{
    Student = await _context.Student.Select(x=>(StudentView)x).ToListAsync();
}

答案 2 :(得分:0)

我也通过在'StudentView'类中实现了从'StudentView'到'Student'的转换,然后使用磁控管解决方案,设法解决了这个问题。

因此,我在“视图”类中实现了转换。为什么我不知道为什么需要这样做,对我来说似乎很神奇,因为对于“学生”到“ StudentView”的转换来说,这种转换是不必要的。也许某处写的东西出于某种原因需要双向转换。

public class StudentView : ViewBase<Student>
{
    // Removed for brevity

    public static implicit operator Student(StudentView student)
    {
        return new Student(student);
    }

}

然后更新了铸造方法,就像磁控管突出显示的那样:

    public async Task OnGetAsync()
    {
        Student = await _context.Student.Select(x => (StudentView)x).ToListAsync();
    }

我还想强调Billybob的答案,因为他提供了另一种解决问题的正确方法,我只是选择了另一种方法。