2016-06-07 4 views
0

Was ich versucheMit MVC Ansicht LabelFor/TextFor mit Ausdruck mit unbekanntem Rückgabetyp

Ich habe einen Web-App zu erreichen, wo der Benutzer ein Verwaltungsportal hat, die verwendet werden kann, bestimmte Einstellungen zu bearbeiten. Es gibt viele bearbeitbare Einstellungen, daher möchte ich einen einzelnen Satz vererbbarer MVC-Objekte erstellen, so dass ich einfach ein Einstellungsobjekt (das nur eine Zeile in einer Tabelle ist) angeben kann und die Einstellungen anzeigen und die Suchfunktionalität anbieten die Fähigkeit, hinzufügen/entfernen von Einträgen usw.

Was ich

Ein vererbbares Controller-Objekt erstellt wurde bisher. Es arbeitet, indem es den Objekttyp (wie ein User Objekt) nimmt und ein Array von AdminField Objekten erstellt. Jeder repräsentiert eine Zeile in der Datenbank. Die abgeleitete Controller-Klasse geht auch Metadaten für jedes Feld als Flags, so die abgeleitete Controller-Code würde wie folgt aussehen:

public class UserController : AdminBaseController<UserViewModel, User> 
{ 
    public UserController(Context context) : 
     base(context, new AdminField<User>[] { 
      new AdminField<User>(u => u.UserId, AdminFieldFlags.Hidden | AdminFieldFlags.IsID), 
      new AdminField<User>(u => u.UserName, AdminFieldFlags.Searchable | AdminFieldFlags.Sortable | AdminFieldFlags.Editable | AdminFieldFlags.EditLink, "User Name"), 
      new AdminField<User>(u => u.Password, AdminFieldFlags.Editable), 
      new AdminField<User>(u => u.AccessLevel, AdminFieldFlags.Editable) 
     }, "User") 
    { 
    } 
} 

Der erste Parameter ist ein Lambda, das zeigt, wie sich aus dem Objekt das referenzierte Feld zu bekommen.

Hier ist die Methode Signatur für den AdminField Konstruktor:

public AdminField(Expression<Func<TMaintainedType, object>> field, AdminFieldFlags flags, string displayName = null) 

Die Felddaten an das Ansichtsmodell auch zugänglich ist, so in der Ansicht wir Code wie dieses:

@foreach (var f in Model.Fields.Where(f => !f.Hidden)) 
{ 
    //Gets original expression for this field 
    var expression = Model.ExpressionFromField<UserViewModel>(f); 
    <div class="form-group"> 
     @Html.LabelFor(expression, new { @class = "control-label col-3" }) 
     @Html.EditorFor(expression, new { htmlAttributes = new { @class = "form-control" } }) 
    </div> 
} 

Viola! Die Feldbezeichnung und das Bearbeitungsfeld werden angezeigt!

Das Problem

die Methodensignatur für AdminField nimmt ein Expression<Func<TMaintainedType, object>> Objekt. Dies funktioniert hervorragend für string s, aber (basierend auf meinem begrenzten Verständnis) erzwingt ein Boxen/Unboxing für int Felder, und damit ändert sich der gespeicherte Ausdruck von (zum Beispiel) u => u.UserId zu u => Convert(u.UserId). Da ich ein Array von Feldern speichern, muss der Rückgabetyp object sein (da es anders sein kann), so dass ich die Convert nicht entfernen kann.

Als Ergebnis, wenn das Feld den Ausdruck und das Feld ist int32 packt, erhalte ich eine System.InvalidOperationException Fehler auf meiner LabelFor Linie: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.

die Frage

Wie ich Expression<Func<T, object>>-Expression<Func<T, int>> umwandeln kann dynamisch?

ich zur Zeit durch die Schaffung einer speziellen Methode nur für ganze Zahlen, um das Problem bekommen, das die Umwandlung entfernt, aber das bedeutet, dass

  1. I für eine ganze Zahl (jedes Mal überprüfen müssen, die für eine LOT macht von If-Anweisungen in den Ansichten) und
  2. Wenn ich einen anderen Werttyp brauche, muss ich noch eine andere spezielle Methode erstellen und switch/if-Anweisungen in den Ansichten verwenden, um die richtige Methode auszuwählen.

Hilfe! Lassen Sie mich wissen, wenn Sie weitere Informationen benötigen; es ist immer schwer zu wissen, was zu berücksichtigen ist.

+0

aus Interesse, warum haben Sie nicht einen Typparameter anstelle von Objekt verwendet? z.B. 'Expression >' –

+0

Der Rückgabetyp ist mit 'AdminField ' verknüpft. Wenn Sie einen Rückgabetyp-Parameter verwenden, müssen Sie dies in 'AdminField ' ändern. Ich brauche Arrays von 'AdminField' Objekten mit unterschiedlichen Rückgabetypen, das funktioniert nicht. Die einzigen Alternativen, die ich mir vorstellen konnte (z. B. Kovarianz), würden nur mit Referenztypen funktionieren, und die meisten meiner Typen sind Werttypen. – Daniel

+0

Ich habe mein Gehirn dazu gebracht, es auszuarbeiten, aber noch keine Würfel; interessante Herausforderung;) –

Antwort

0

Ich konnte diese Konvertierung nicht dynamisch vornehmen, löste jedoch mein Problem mit dem detaillierten Ansatz here.

Ich habe die Objekte HtmlHelper aufgegeben und stattdessen die name Eigenschaften von HTML-Elementen verwendet, um Werte an das Datenmodell zu binden. Weil die name eine string ist, könnte ich alles in eine string umwandeln, die mein Datentypenproblem löst. Die MVC-Bindung übernimmt die Konvertierung der bearbeiteten Werte in ihre ursprünglichen Typen. Die Kombination bietet mir eine wechselseitige Unterstützung für alle meine benötigten Datentypen (string s, Werttypen und nullable Werttypen).

Verwandte Themen