4

次の2つのプロパティを使用してモデルをバインドしようとすると、モデルのバインド中にエラーが発生します。

    private IEnumerable<Claimant> _drivers;
    public IEnumerable<Claimant> Drivers
    {
        get
        {
            return _drivers ?? Enumerable.Empty<Claimant>();
        }
        set
        {
            _drivers = value;
        }
    }

    private IEnumerable<Property> _vehicles;
    public IEnumerable<Property> Vehicles
    {
        get
        {
            return _vehicles ?? Enumerable.Empty<Property>();
        }
        set
        {
            _vehicles = value;
        }
    }

エラー:

System.Reflection.TargetInvocationException was unhandled by user code
  Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
       <snip>
  InnerException: System.NotSupportedException
       Message=Collection is read-only.
       Source=mscorlib
       StackTrace:
            at System.SZArrayHelper.Clear[T]()
            at System.Web.Mvc.DefaultModelBinder.CollectionHelpers
                         .ReplaceCollectionImpl[T](ICollection`1 collection, IEnumerable newContents)
       InnerException: 

プロパティを基本的な自動プロパティに変更した場合:

    public IEnumerable<Claimant> Drivers { get; set; }
    public IEnumerable<Property> Vehicles { get; set; }

すべてが正常に動作します。

セッターが自動プロパティセッターと同じである場合、モデルバインディングに問題があるのはなぜですか?

編集-デフォルトのモデルバインダーソースを読むと、最終的にこれにつながります。最初の行はClear()プロパティに対して呼び出しているため、戻ったときにEmpty<T>明らかに機能しません。

private static void ReplaceCollectionImpl<T>(ICollection<T> collection, IEnumerable newContents) 
{
    collection.Clear();
    if (newContents != null) 
    {
        foreach (object item in newContents) 
        {
            // if the item was not a T, some conversion failed. the error message will be propagated,
            // but in the meanwhile we need to make a placeholder element in the array.
            T castItem = (item is T) ? (T)item : default(T);
            collection.Add(castItem);
        }
    }
}
4

4 に答える 4

6

このようにしてみてください:

get 
{
    return _drivers ?? new List<Claimant>();
}
于 2012-06-18T15:06:52.177 に答える
5

IIRCEnumerable.Empty<T>は静的な読み取り専用の列挙型であり、空のストレージに依存しない列挙型をメソッドに渡すために使用されます。空のコレクションの「開始点」として使用するためのものではありません。これが、エラーが発生する理由である可能性があります。

ストレージメカニズム(例List<T>)を選択し、それをバッキングフィールドのタイプとして使用します。その後、初期化することができます

  1. クラス定義では、
  2. コンストラクターで、または
  3. 最初に取得:

例:

private List<Claimant> _drivers = new List<Claimamt>();  // Option 1

public MyModel()
{
    _drivers = new List<Claimant>();   // Option 2
}

public IEnumerable<Claimant> Drivers
{
    get
    {
        return _drivers ?? (_drivers = new List<Claimant>()); // Option 3
    }
    set
    {
        _drivers = value;
    }
}
于 2012-06-18T15:22:42.670 に答える
1

カスタムゲッターでは、通常、null合体演算子(??)を使用して、戻ったときにプライベートバッキングフィールドを設定します。

private IEnumerable<Claimant> _drivers;
public IEnumerable<Claimant> Drivers
{
    get
    {
        return _drivers ?? (_drivers = Enumerable.Empty<Claimant>());
    }
    set
    {
        _drivers = value;
    }
}

デフォルト値を空の配列に設定することもできます。

(_drivers = new Claimant[]{})
于 2012-06-18T15:07:59.133 に答える
1

問題の原因となっている正確なプロパティ名とタイプを確認してください。

public class TestBinder: DefaultModelBinder
{
    public override object BindModel(
            ControllerContext controllerContext,
            ModelBindingContext bindingContext)
    {
        Debug.WriteLine(bindingContext.ModelName);
        Debug.WriteLine(bindingContext.ModelType.ToString());

        //HOW TO USE: Look at your Output for the most recently output ModelName and Type to determine where there problem lies

        return base.BindModel(controllerContext, bindingContext);
    }
}

このバインダーをデフォルトとして設定します。

ModelBinders.Binders.DefaultBinder = new TestBinder();
于 2016-02-13T06:50:22.387 に答える