将 ISomeInterface> 转换为 ISomeInterface
本文关键字:ISomeInterface object 转换 bool Nullable | 更新日期: 2023-09-27 18:35:22
我有一个自定义的HtmlHelper,我试图在其中获取泛型类型属性的值。My ViewModel 具有 ChangeRequestFormField 类型的属性。 我的 ViewModel、类/接口和 html 助手的相关部分如下所示。
在我的帮助程序中,我需要从我的 ViewModel 属性访问 IsRequired 和 ValueHasChanged 属性。 这对于 ChangeRequestFormField 工作正常。 但是当我到达ChangeRequestFormField时,我收到以下错误:
无法强制转换类型的对象 'StaffChanges.Models.ChangeRequestFormField
1[System.Nullable
1[System.Boolean]]' 要键入 'StaffChanges.Models.IChangeRequestFormField'1[System.Object]'.
错误发生在帮助程序的以下行:
var isRequired = ((IChangeRequestFormField<object>)metadata.Model).IsRequired;
也许我的做法是错误的,但我需要一种方法来访问帮助程序中的这些属性,直到运行时才知道 ChangeFormField 中的类型。
视图模型:
public class JobChangeModel
{
public ChangeRequestFormField<string> Reason1 { get; set; }
public ChangeRequestFormField<bool?> IsTransferEventNeeded { get; set; }
}
public class ChangeRequestFormField<T> : IChangeRequestFormField<T>
{
public ChangeRequestFormField(string formFieldType, T fieldValue, T originalValue)
{
this.FieldValue = fieldValue;
this.OriginalValue = originalValue;
switch (formFieldType)
{
case FormFieldTypes.DoNotRender:
this.RenderField = false;
this.IsRequired = false;
break;
case FormFieldTypes.Required:
this.RenderField = true;
this.IsRequired = true;
break;
case FormFieldTypes.Optional:
this.RenderField = true;
this.IsRequired = false;
break;
default:
this.RenderField = false;
this.IsRequired = false;
break;
}
}
public T FieldValue { get; set; }
public bool IsRequired { get; private set; }
public T OriginalValue { get; set; }
public string OriginalValueString
{
get
{
return this.OriginalValue == null ? string.Empty : this.OriginalValue.ToString();
}
}
public bool ValueHasChanged
{
get
{
return !EqualityComparer<T>.Default.Equals(this.FieldValue, this.OriginalValue);
}
}
}
public interface IChangeRequestFormField<out T>
{
bool IsRequired { get; }
string OriginalValueString { get; }
bool ValueHasChanged { get; }
}
public static MvcHtmlString LabelForChangeRequestFormField<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string labelText, IDictionary<string, object> htmlAttributes)
{
if (expression.Body.Type.GetGenericTypeDefinition() != typeof(ChangeRequestFormField<>))
{
return html.LabelFor(expression, htmlAttributes);
}
var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
var isRequired = ((IChangeRequestFormField<object>)metadata.Model).IsRequired;
var valueChanged = ((IChangeRequestFormField<object>)metadata.Model).ValueHasChanged;
// other code left out
}
根据您的代码,IChangeRequestFormField
接口似乎不需要是通用的。如果从接口声明中删除类型参数T
,您将能够将所有派生泛型类强制转换为非泛型接口。
public interface IChangeRequestFormField
{
bool IsRequired { get; }
string OriginalValueString { get; }
bool ValueHasChanged { get; }
}
public class ChangeRequestFormField<T> : IChangeRequestFormField
{
// ...
}
然后,您可以像这样使用它:
var isRequired = ((IChangeRequestFormField)metadata.Model).IsRequired;
如果您需要在界面中使用泛型类型,事情会变得更加复杂。然后,您需要小心如何实现接口的协变或逆变方面,以支持所需的转换行为。看看这篇关于 MSDN 的文章。
注意
特别是,协变接口不起作用的原因是存在协变类型必须是引用类型的限制。由于Nullable<T>
不是引用类型,因此强制转换失败。
如果您发现确实需要协变行为,则可以实现自己的可为空的引用类型来包装值类型,例如 bool
和 int
。