2010-08-05 7 views
12

Es uno de los parámetros proporcionados al método CreateMetadata (que se reemplaza si se amplía la compatibilidad con metadatos).¿Qué es el parámetro "Func <object> modelAccessor" para en el DataAnnotationsModelMetadataProvider de MVC?

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

Yo había asumido que permitía el acceso al propio modelo de objetos (por ejemplo, para el establecimiento de metadatos basado en los valores de modelo), sin embargo cuando intento usarlo para lanzar al modelo de objetos apenas consigo nula.

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

Si no lo he entendido, ¿alguien puede explicar cuál es su propósito? O alternativamente, ¿cómo usarlo correctamente?

Gracias

Respuesta

2

parámetro El modelAccessor no apunta a una instancia del objeto, sino que es una función que tendrá acceso a algún atributo de su objeto. El Func "encapsula un método que no tiene parámetros y devuelve un valor del tipo especificado por el parámetro TResult". Por ejemplo, si tenemos la clase siguiente:

public class Bar(){ 

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

Cuando el CreateMetaData se llama, que será la creación de metadatos para la propiedad y la Foo modelAccessor será una función que devuelve el valor de Foo.

Hice un poco de excavación y encontré una manera de llegar a la instancia del objeto, pero requiere el uso de la reflexión. Puede hacer lo siguiente para obtener la clase Bar en mi ejemplo:

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); 
} 

Yo sólo he encontrado esto en contra de un caso de prueba simple, por lo que su experiencia puede variar, pero espero que esto ayudará a aclarar lo que está pasando.

7

Originalmente teníamos eso como "modelo de objeto", en lugar de "Func modelAccessor". Tuvimos que cambiarlo tarde en el ciclo de envío de MVC 2.

El propósito es retrasar la recuperación del valor real del modelo hasta el punto que sabe que va a necesitarlo (es decir, hasta que llame a ModelMetadata.Model).

El problema que resuelve es en realidad uno bastante esotérico relacionado con el enlace del modelo contra una clase LINQ a SQL que tiene una referencia de clave foránea en él. El problema es que si recuperaste el objeto hijo que está representado por una relación de clave externa (lo que generalmente significa una carga de retraso de ese objeto), entonces ya no puedes elegir un nuevo objeto secundario configurando la clave externa Propiedad de ID. Es muy común modelar la identificación de clave externa (y no la entidad de clave externa completa) cuando se vincula el modelo, pero si hubiésemos recuperado el objeto de entidad de clave externa (para completar la clase ModelMetadata) esa vinculación ya no sería ser legal, y lanzar una excepción. Debido a que ModelMetadata se usa para ambas direcciones de modelos (entrante, vinculante y saliente mediante generación de HTML), necesitamos introducir la capa de indirección para proteger su capacidad de usarla en ambos escenarios sin interrumpir las reglas de LINQ to SQL.

+0

Acabo de jugar con esto y el delegado parece ser nulo cuando estoy renderizando un Editor para modelo. ¿Hay alguna forma de obtener el objeto que se está procesando para que pueda tener metadatos dinámicos? – mcintyre321

+1

, ¿hay alguna forma de acceder a la instancia de objeto del contenedor? – Darragh

+0

No como de MVC 3. –

Cuestiones relacionadas