Для чего нужен параметр «Func <object>modelAccessor» в DataAnnotationsModelMetadataProvider MVC? - PullRequest
12 голосов
/ 05 августа 2010

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

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

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

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

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

Спасибо

Ответы [ 2 ]

7 голосов
/ 14 августа 2010

У нас изначально это было как "объектная модель", а не как "Func modelAccessor".Мы должны были изменить его в конце цикла кораблей MVC 2.

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

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

2 голосов
/ 14 августа 2010

Параметр 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);
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...