HtmlHelper关于通用视图模型的类型参数

本文关键字:类型参数 模型 视图 于通用 HtmlHelper | 更新日期: 2023-09-27 18:04:13

我试图在强类型视图上创建一个HtmlHelper方法,其中视图模型是通用的。但是有一个复杂的问题。我想简化语法,以便可以在视图模型上指定属性的成员表达式。

public interface ViewModel<T>
{
    T Model { get; set; }
}
public class DocViewModel : ViewModel<Document> 
{
    public IEnumerable<string> Options { get; set; }
    public Document Model { get; set; }
}
public class Document
{
    public string Name { get; set; }
    public string Value { get; set; }
}

现在,我可以很容易地创建一个引用视图模型本身的帮助器,并像这样使用它:

@model DocViewModel
<div>
    @Html.DoSomething(vm => vm.Options);
    @Html.DoSomethingElse(vm => vm.Model.Name);
    @Html.DoSomethingYetAgain(vm => vm.Model.Value);
</div>

但是我希望能够在模型上简单地传递一个表达式,像这样:

@model DocViewModel
<div>
    @Html.DoSomething(vm => vm.Options);
    @Html.DoSomethingElse(vm => vm.Name);
    @Html.DoSomethingYetAgain(vm => vm.Value);
</div>

现在,我可以用这样一种方式编写帮助器,如果我在调用中显式引用类型参数,我就可以这样做:

@model DocViewModel
<div>
     @Html.DoSomething<Document>(vm => vm.Name);
</div>

但是那有点违背了我所追求的目的。似乎我应该能够编写一个HtmlHelper,可以利用视图是强类型的DocViewModel,它本身就是一个ViewModel,并且@Html()返回

HtmlHelper<DocViewModel> //HtmlHelper<ViewModel<Document>>

使Document所表示的类型参数隐式已知,这样我就可以写

public static string DoSomethingElse<TModel, TProperty>(this HtmlHelper<ViewModel<TModel>> helper, Expression<Func<TModel, TProperty>> expression) 
{
    return "Whatever";
}

,但这种转换不能完成。有什么办法可以帮我吗?还是我只能忍受这些丑陋的语法?

编辑:将不正确的引用"KoViewModel"改为"ViewModel"

再次编辑:此外,使ViewModel泛型的要点是,我可以声明任何其他类型的ViewModel:

public class ProgramViewModel : ViewModel<Program>
{
    //other stuff
    public Program Model { get; set; }
}
public class Program
{
    public string Something { get; set; }
    //other properties I want to reference
}

和另一个视图:

@model ProgramViewModel
<div>
    @Html.DoSomethingElse(vm => vm.Something)
</div>

再次强调,我希望能够在视图的视图模型和视图模型的Model属性上解引用属性,而不必在方法调用中显式引用类型。

我上面定义的方法的问题是,在HtmlHelper和HtmlHelper之间显然没有隐式转换,因此编译器不能像上面那样解决视图中的@Html调用("不包含定义和没有扩展方法blah blah")。当然,所有的显式强制转换都可以使其工作,但这正是我试图避免的。

HtmlHelper关于通用视图模型的类型参数

如果您可以将ViewModel更改为抽象类,请执行以下操作:

public abstract class ViewModel<TModel>
{
    public class HtmlHelper : HtmlHelper<ViewModel<TModel>> {}
    public TModel Model;
}

然后编写如下静态扩展方法:

public static TProperty DoSomethingElse<TModel, TProperty>(this ViewModel<TModel>.HtmlHelper helper, Expression<Func<TModel, TProperty>> expression) 
{
    return default(TProperty);
}