3

在我的模型类中,我有多个“受保护的内部集”属性。一旦创建了这些属性,就不能对其进行修改。话虽如此,我很难创建允许在创建时设置这些属性的模型绑定器。为了能够只设置一次这些属性,最好的方法是什么?

4

3 回答 3

1

不幸的是,这不是您可以自动完成的。您必须为每种类型创建一个唯一的模型绑定器,然后使用构造函数参数创建对象。

于 2012-05-29T15:24:50.643 回答
1

我使用自定义模型绑定器做到了这一点。我不仅有私有设置器,而且我的 MVC 操作的参数是一个接口,而且我没有无参数构造函数(三连胜!);这些都不适用于默认模型绑定器。

在您的情况下,您只需为您的类型制作一个自定义模型绑定器。使用默认值创建您的类的新实例。然后只需使用反射来设置类的属性。反射方法不关心属性的可访问性。像这样的东西:

// assuming your class looks like this
public class MyClass
{
    public int MyInt { get; private set; }
    public string MyString { get; private set; }

    public MyClass(int myInt, string myString)
    {
        MyInt = myInt;
        MyString = myString;
    }
}

// model binder is like this
public class MyModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext,
        ModelBindingContext bindingContext,
        Type modelType)
    {
        // initialize with default values, they will be overwritten
        MyClass myClass = new MyClass(default(int), default(string));
        // get the reflection info on the int property
        PropertyInfo intProperty = typeof(MyClass).GetProperty("MyInt");
        // get the int value from the request
        int myIntValue = int.Parse(bindingContext.ValueProvider
            .GetValue(intProperty.Name).AttemptedValue);
            // btw, attempted value is a string
        // set the property value, SetValue ignores accessibility modifiers
        intProperty.SetValue(myClass, myIntValue, null);
        // do the same stuff for MyString property
        PropertyInfo stringProperty = typeof(MyClass).GetProperty("MyString");
        string myStringValue = bindingContext.ValueProvider
            .GetValue(stringProperty.Name).AttemptedValue;
        stringProperty.SetValue(myClass, myStringValue, null);
        return myClass;
    }
}

// Your controller action is like this
public ActionResult MyAction([ModelBinder(typeof(MyModelBinder))]
                             MyClass myClass)
{
    ...
}

我想你可以在不使用反射来设置它们的情况下将正确的值传递给构造函数:

        ...
        int myIntValue = int.Parse(bindingContext.ValueProvider
            .GetValue(intProperty.Name).AttemptedValue);
        string myStringValue = bindingContext.ValueProvider
            .GetValue(stringProperty.Name).AttemptedValue;
        MyClass myClass = new MyClass(myIntValue, myStringValue);
        ...

但是如果您需要做更多事情,反射可以让您绕过访问修饰符限制(当然是出于有效的基础设施原因!:D)。在我的例子中,我不想为每个可以实现接口的类编写模型绑定器,所以我使用了更多的反射来匹配类,找到一个构造函数,将默认值传递给它,然后循环遍历每个属性类并从请求值中设置它。我有一个单独的方法可以在运行基于消息的操作之前验证消息。

于 2012-08-13T00:50:18.687 回答
0

仅当尚未设置私有字段时,您是否可以保护设置方法设置私有字段?

public string PropertyName
{
  get
  {
     return this.privateField;
  }

  protected set
  {
     if (this.privateField == null)
     {
       this.privateField = value;
     }

  }
}

private string privateField;
于 2012-05-30T11:08:36.533 回答