我正在尝试编写一个通用(在许多地方有用)控件,我可以在整个公司中重复使用。
我在视图和viewmodel中遇到了实际的C#泛型问题。
以下是我正在尝试做的一个例子:
通用部分视图:(_Control.cshtml
)
@model SimpleExample<dynamic>
@Model.HtmlTemplate(Model.Data)
ViewData:(SimpleExample.cs
)
public class SimpleExample<T>
{
public T Data;
public Func<T, System.Web.WebPages.HelperResult> HtmlTemplate;
}
用法示例:(FullView.cshtml
)
@model Foo.MyViewData
@Html.Partial("_Control", new SimpleExample<MyViewData>
{
Data = Model,
HtmlTemplate = @<div>@item.SomeProperty</div>
})
我正在寻找的功能的重要部分是消费者在编写Html内联时获取一个类型化对象,以便他们可以使用Intellisense(如FullView.cshtml
中所示)。
所有内容编译良好且智能感知正在运行,但我将错误视为运行时:
The model item passed into the dictionary is of type
'AnytimeHealth.Web.ViewData.SimpleExample`1[Foo.MyViewData]',
but this dictionary requires a model item of type
'AnytimeHealth.Web.ViewData.SimpleExample`1[System.Object]'.
我已经读过,我可以在我的通用类型上使用covarience来实现这一点,但我不知道该怎么做。
你能告诉我如何才能让它发挥作用吗?
答案 0 :(得分:3)
更改_Control.cshtml
中的定义:
更改此@model SimpleExample<dynamic>
到@model dynamic
它会起作用,但会丢失SimpleExample
和
MyViewData
的intellisense仍然有效。
我认为这是因为动态类型将在运行时知道,但是泛型的类型
需要早期(可能是编译时间),此时只有object
是已知的。
答案 1 :(得分:3)
您可以使用通用对象,然后使用反射渲染此对象的属性(使用帮助程序列出属性)。这与Twitter Bootstrap用于MVC 4的方法相同(为方便起见,此代码的部分内容已被复制):http://nuget.org/packages/twitter.bootstrap.mvc4
_Control.cshtml
@model Object
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
<fieldset>
<legend>@Model.GetLabel()</legend>
@foreach (var property in Model.VisibleProperties())
{
using(Html.ControlGroupFor(property.Name)){
@Html.Label(property.Name)
@Html.Editor(property.Name)
@Html.ValidationMessage(property.Name, null)
}
}
<button type="submit">Submit</button>
</fieldset>
}
Helper.cs
public static string GetLabel(this PropertyInfo propertyInfo)
{
var meta = ModelMetadataProviders.Current.GetMetadataForProperty(null, propertyInfo.DeclaringType, propertyInfo.Name);
return meta.GetDisplayName();
}
public static PropertyInfo[] VisibleProperties(this IEnumerable Model)
{
var elementType = Model.GetType().GetElementType();
if (elementType == null)
{
elementType = Model.GetType().GetGenericArguments()[0];
}
return elementType.GetProperties().Where(info => info.Name != elementType.IdentifierPropertyName()).ToArray();
}
public static PropertyInfo[] VisibleProperties(this Object model)
{
return model.GetType().GetProperties().Where(info => info.Name != model.IdentifierPropertyName()).ToArray();
}