0

I have a custom HtmlHelper where I am trying to get values of a generic type property. My ViewModel has properties of type ChangeRequestFormField. The relevant parts of my ViewModel, class/interface, and the html helper are shown below.

In my helper, I need to access the IsRequired and ValueHasChanged properties from my ViewModel properties. This is working fine for ChangeRequestFormField. But when I get to ChangeRequestFormField, I get a the following error:

Unable to cast object of type 'StaffChanges.Models.ChangeRequestFormField1[System.Nullable1[System.Boolean]]' to type 'StaffChanges.Models.IChangeRequestFormField`1[System.Object]'.

The error occurs at this line in the helper:

var isRequired = ((IChangeRequestFormField<object>)metadata.Model).IsRequired;

Maybe I'm approaching this wrong, but I need a way to access those properties in the helper, not knowing the type in the ChangeFormField until runtime.

ViewModel:

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
}

Laravel does not automatically map routes in controller/method fashion.

You have not posted what is in your routes.php file, but one of the simplest approaches is to do this:

Route::get('users/login', array('as' => 'login', 'uses' => 'User@getLogin'));

There are multiple approaches, though. You might consider reading the docs about routing

4

1 に答える 1

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;

インターフェイスでジェネリック型が必要な場合、事態はさらに複雑になります。次に、インターフェイスの共変または反変の側面を実装して、目的のキャスト動作をサポートする方法に注意する必要があります。MSDNのこの記事をご覧ください。

ノート

特に、共変インターフェースが機能しない理由は、共変型が参照型でなければならないという制限があるためです。は参照型ではないためNullable<T>、キャストは失敗します。

共変の動作が本当に必要であることがわかった場合は、独自の null 許容参照型を実装して、boolやなどの値型をラップできますint

于 2013-10-15T15:25:48.217 に答える