Подтвердить что ты не робот

Что такое параметр "Func <object> modelAccessor" для MVC DataAnnotationsModelMetadataProvider?

Это один из параметров, предоставляемых методу CreateMetadata (который вы переопределяете, если расширяете поддержку метаданных).

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

Я предположил, что он позволил вам получить доступ к самому объекту модели (например, для установки метаданных на основе значений модели), однако, когда я пытаюсь использовать его для приведения к объекту модели, я просто получаю null.

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

Если я пропустил понимание, может ли кто-нибудь объяснить, что это за цель? Или, альтернативно, как правильно его использовать?

Спасибо

4b9b3361

Ответ 1

Первоначально у нас это было как "объектная модель", а не "Func modelAccessor". Нам пришлось изменить его в конце цикла корабля MVC 2.

Цель состоит в том, чтобы отложить получение фактического значения модели до тех пор, пока вы не знаете, что она вам понадобится (то есть до тех пор, пока вы не назовете ModelMetadata.Model).

Проблема, которую он решает, на самом деле довольно эзотерическая, связанная с привязкой модели к классу LINQ to SQL, в которой есть ссылка внешнего ключа. Проблема в том, что если вы получили дочерний объект, который представлен отношением внешнего ключа (что обычно означает задержку загрузки этого объекта), вам больше не разрешается выбирать новый дочерний объект, задав внешний ключ ID. Очень часто для модели привязывать идентификатор внешнего ключа (а не весь внешний объект ключа) при привязке модели, но если бы мы извлекли объект сущности внешнего ключа (для заполнения класса ModelMetadata), то это связывание больше не будет быть законным и фактически вызывать исключение. Поскольку ModelMetadata используется для обоих направлений моделей: входящие, через привязку модели и исходящие, посредством генерации HTML - нам нужно было ввести слой косвенности, чтобы защитить вашу способность использовать его в обоих сценариях, не нарушая правил LINQ to SQL.

Ответ 2

Параметр modelAccessor не указывает на экземпляр объекта, а скорее представляет собой функцию, которая будет обращаться к некоторому атрибуту вашего объекта. Func "инкапсулирует метод, который не имеет параметров и возвращает значение типа, заданного параметром TResult." Например, если у нас следующий класс:

public class Bar(){

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

Когда вызывается CreateMetaData, это будет создание метаданных для свойства Foo, а modelAccessor будет функцией, которая возвращает значение Foo.

Я немного поработал и нашел способ добраться до экземпляра объекта, но для этого требуется использовать отражение. Вы можете сделать следующее, чтобы получить класс Bar в моем примере:

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

Я только запускаю это против простого тестового примера, поэтому ваш пробег может отличаться, но, надеюсь, это поможет прояснить, что происходит.