2010-08-05 7 views
12

È uno dei parametri forniti per il metodo CreateMetadata (che si sovrascrive se si estende il supporto dei metadati).Qual è il parametro "Func <object> modelAccessor" per in DataAnnotationsModelMetadataProvider di MVC?

ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, 
          Type containerType, 
          Func<object> modelAccessor, <<--THIS ONE 
          Type modelType, 
          string propertyName) 

ho dato per scontato che ci ha permesso di accedere all'oggetto modello stesso (ad esempio, per impostare i metadati sulla base dei valori del modello), ma quando cerco di usarlo per lanciare al mio modello oggetto ottengo solo null.

Entity ent = (Entity)modelAccessor(); // = Null 

Se ho incompreso, qualcuno può spiegare qual è lo scopo? O in alternativa, come usarlo correttamente?

Grazie

risposta

2

parametro Il modelAccessor non punta a un'istanza dell'oggetto, ma è una funzione che accedere ad alcuni attributi dell'oggetto. Il Func "incapsula un metodo che non ha parametri e restituisce un valore del tipo specificato dal parametro TResult." Per esempio, se abbiamo seguenti classi:

public class Bar(){ 

    [DisplayName("I am Foo.")] 
    public string Foo{get;} 
} 

Quando il CreateMetaData si chiama, sarà di creare metadati per la proprietà Foo e il modelAccessor sarà una funzione che restituisce il valore di Foo.

Ho fatto un po 'di scavo e ho trovato un modo per arrivare all'istanza dell'oggetto, ma richiede l'uso del riflesso. È possibile effettuare le seguenti operazioni per ottenere la classe Bar nel mio esempio:

if (modelAccessor != null) 
{ 
    //Use reflection to get the private field that holds the Bar object. 
    FieldInfo container = modelAccessor.Target.GetType().GetField("container"); 

    //Invoke field on the modelAccessor target to get the instance of the Bar object. 
    Bar myObject = (Bar)container.GetValue(modelAccessor.Target); 
} 

Ho eseguito solo questo contro un semplice caso di test, così il vostro chilometraggio può variare, ma spero che questo aiuterà a chiarire ciò che sta accadendo.

7

Inizialmente l'avevamo come "modello di oggetto", anziché "Func modelAccessor". Abbiamo dovuto cambiarlo in ritardo nel ciclo di spedizione di MVC 2.

Lo scopo è di ritardare il recupero del valore effettivo del modello fino a quando non si sa che ne avrete bisogno (ovvero, fino a quando non si chiama ModelMetadata.Model).

Il problema che risolve è in realtà piuttosto esoterico relativo al collegamento del modello a una classe LINQ to SQL che contiene un riferimento di chiave esterna. Il problema è che, se hai recuperato l'oggetto figlio rappresentato da una relazione di chiave esterna (che di solito significa un carico ritardato di quell'oggetto), non ti è più consentito scegliere un nuovo oggetto figlio impostando la chiave esterna Proprietà ID. È molto comune modellare il binding dell'ID chiave esterna (e non dell'intera entità chiave esterna) durante l'associazione modello, ma se avessimo recuperato l'oggetto entità chiave esterna (ai fini del popolamento della classe ModelMetadata), tale associazione non sarebbe più essere legale e in effetti lanciare un'eccezione Poiché ModelMetadata è utilizzato per entrambe le direzioni dei modelli - in entrata, tramite associazione modello e in uscita, tramite generazione HTML - abbiamo dovuto introdurre il livello di riferimento indiretto per proteggere la possibilità di utilizzarlo in entrambi gli scenari senza interrompere LINQ alle regole SQL.

+0

Ho appena giocato con questo e il delegato sembra essere nullo quando sto riproducendo un EditorForModel. C'è un modo per ottenere l'oggetto che viene reso in modo che possa avere metadati dinamici? – mcintyre321

+1

quindi è comunque necessario accedere all'istanza dell'oggetto del contenitore? – Darragh

+0

Non a partire da MVC 3. –

Problemi correlati