MVC的DataAnnotationsModelMetadataProvider中的“Func <object> modelAccessor”参数是什么?</object>

时间:2010-08-05 06:56:36

标签: asp.net-mvc-2

这是提供给CreateMetadata方法的参数之一(如果扩展元数据支持,则会覆盖它)。

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

我曾假设它允许您访问模型对象本身(例如,根据模型值设置元数据),但是当我尝试使用它来转换为我的模型对象时,我只得到null。

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

如果我误解了,有人可以解释它的目的是什么吗?或者,如何正确使用它?

由于

2 个答案:

答案 0 :(得分:7)

我们最初将其作为“对象模型”,而不是“Func modelAccessor”。我们不得不在MVC 2的船舶周期中改变它。

目的是延迟检索模型的实际值,直到你知道你将需要它为止(也就是说,直到你调用ModelMetadata.Model)。

它解决的问题实际上是一个相当深奥的问题,它涉及到LINQ to SQL类的模型绑定,其中包含一个外键引用。问题是,如果您检索到由外键关系表示的子对象(通常意味着该对象的延迟加载),则不再允许您通过设置外键来选择新的子对象身份证。在模型绑定时模拟绑定外键ID(而不是整个外键实体)是很常见的,但是如果我们检索了外键实体对象(为了填充ModelMetadata类)那么该绑定将不再是合法的,实际上是一个例外。由于ModelMetadata用于模型的两个方向 - 入站,通过模型绑定和出站,通过HTML生成 - 我们需要引入间接层以保护您在两种情况下使用它的能力,而不会破坏LINQ to SQL的规则。

答案 1 :(得分: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);
}

我只是针对一个简单的测试用例运行,所以你的里程可能会有所不同,但希望这有助于澄清发生了什么。