3

私のモデルクラスには、「保護された内部セット」である複数のプロパティがあります。これらのプロパティが作成されると、変更できなくなります。作成時にこれらのプロパティを設定できるようにするモデル バインダーを作成するのに苦労しています。これらのプロパティを 1 回だけ設定できるようにするための最善の方法は何ですか?

4

3 に答える 3

1

カスタムモデルバインダーを使用してこれを行いました。プライベート セッターがあるだけでなく、MVC アクションへの引数がインターフェイスであり、パラメーターのないコンストラクター (trifecta!) がありませんでした。デフォルトのモデルバインダーではどれも機能しません。

あなたの場合、あなたのタイプのカスタム モデル バインダーを作成するだけです。クラスの新しいインスタンスをデフォルト値で作成します。次に、リフレクションを使用してクラスのプロパティを設定します。リフレクション メソッドは、プロパティのアクセシビリティを気にしません。このようなもの:

// 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 に答える
1

残念ながら、これは自動的に実行できるものではありません。型ごとに一意のモデル バインダーを作成し、コンストラクター パラメーターを使用してオブジェクトを作成する必要があります。

于 2012-05-29T15:24:50.643 に答える
0

まだ設定されていない場合にのみ、プライベート フィールドを設定する set メソッドを保護できますか?

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 に答える