2013-10-15 29 views
0

我有一個自定義的HtmlHelper,我試圖獲取泛型類型屬性的值。 我的ViewModel具有ChangeRequestFormField類型的屬性。下面顯示了我的ViewModel,類/接口和html助手的相關部分。Cast ISomeInterface <Nullable <bool>> to ISomeInterface <object>

在我的幫手中,我需要從我的ViewModel屬性訪問IsRequired和ValueHasChanged屬性。這對ChangeRequestFormField工作正常。但是當我到達ChangeRequestFormField,我收到了以下錯誤:

Unable to cast object of type 'StaffChanges.Models.ChangeRequestFormField 1[System.Nullable 1[System.Boolean]]' to type '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 
} 

回答

1

它看起來並不像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; 

,事情就是否需要泛型類型的接口更加複雜。然後,您需要小心如何實現界面的協變或逆變方面,以支持所需的投射行爲。看看this article on MSDN

注意

特別是你的協接口不工作的原因是因爲是有限制的協變類型必須是引用類型。並且由於Nullable<T>不是引用類型,因此投射失敗。

如果您發現確實需要協變行爲,則可以實現自己的可空引用類型來包裝值類型,如boolint

+0

明白了。當訪問ValueHasChanged時,我需要訪問泛型類型。我在想,既然給定類型T在這個應用程序中會相當有限,我可以對metadata.Model進行類型檢查並進行相應的轉換。我只是試圖保持它比這更好。 –

+0

我利用你的解決方案讓我走了,它的工作原樣。非常感謝! –

+0

太棒了!我很高興它的工作。 –

相關問題