3

我正在尝试为抽象类制作活页夹。绑定器决定使用哪个类的实现。

public abstract class Pet
{
    public string name { get; set; }
    public string species { get; set; }
    abstract public string talk { get; }
}

public class Dog : Pet
{
    override public string talk { get { return "Bark!"; } }
}
public class Cat : Pet
{
    override public string talk { get { return "Miaow."; } }
}
public class Livestock : Pet
{
    override public string talk { get { return "Mooo. Mooo. Fear me."; } }
}

所以我有一个带宠物的控制器,绑定器决定(取决于物种字符串)它是狗、猫还是牲畜。

public class PetBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var values = (ValueProviderCollection)bindingContext.ValueProvider;
        var name = (string)values.GetValue("name").ConvertTo(typeof(string));
        var species = (string)values.GetValue("species").ConvertTo(typeof(string));
        if (species == "dog")
        {
            return new Dog { name = name, species = "dog" };
        }
        else if (species == "cat")
        {
            return new Cat { name = name, species = "cat" };
        }
        else
        {
            return new Livestock { name = name, species = species };
        }
    }
}


public class HomeController : Controller
{
    public JsonResult WorksFine(Pet pet)
    {
        return Json(pet);
    }

    public JsonResult DoesntWork(List<Pet> pets)
    {
        return Json(pets);
    }
}

这很好用,但只要宠物在另一个结构(如List<Pet>或另一个对象)中,我就会得到一个 NullReferenceException(在var name = (string)values.GetValue("name").ConvertTo(typeof(string)); PetBinder 的行上)。我究竟做错了什么?

我添加了一个 Person 类来测试。它还给了我一个 NullReferenceException。

public class Person
{
    public string name { get; set; }
    public Pet pet { get; set; }
}
public class HomeController : Controller
{
    public JsonResult PersonAction(Person p)
    {
        return Json(p);
    }
}

ccurrens 说var name = (string)values.GetValue("name").ConvertTo(typeof(string)); 返回 null 的原因是它无法从列表中获取值。

我看到它们被命名[n].name并且[n].species在 a 中List<Pet>,但是在Person对象中它们被命名pet.name并且pet.species当它们在单个 中时Pet,它们只是被命名为nameand species

解决方案

为了获得具有正确前缀([n]pet其他任何东西)的参数名称GetValue,我使用了以下代码:

bool hasPrefix = bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName);
string prefix = ((hasPrefix)&&(bindingContext.ModelName!="")) ? bindingContext.ModelName + "." : "";

如果有人有兴趣,我最终继承了DefaultModelBinder使用类似于这个答案的东西。这是我使用的完整代码:

public class DefaultPetBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext,ModelBindingContext bindingContext,Type modelType)
    {
        //https://stackoverflow.com/questions/5460081/asp-net-mvc-3-defaultmodelbinder-inheritance-problem

        bool hasPrefix = bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName);
        string prefix = ((hasPrefix)&&(bindingContext.ModelName!="")) ? bindingContext.ModelName + "." : "";

        // get the parameter species
        ValueProviderResult result;
        result = bindingContext.ValueProvider.GetValue(prefix+"species");


        if (result.AttemptedValue.Equals("cat"))
            return base.CreateModel(controllerContext,bindingContext,typeof(Cat));
        else if (result.AttemptedValue.Equals("dog"))
            return base.CreateModel(controllerContext,bindingContext,typeof(Dog));
        return base.CreateModel(controllerContext, bindingContext, typeof(Livestock)); // livestock
    }  

}
4

1 回答 1

0

在您收到错误的行中,values可能为 null 或GetValue("name")返回的内容可能为 null。

我假设当您调用该List<Pet>方法时, ValueProvider 返回整个List而不是每个 individual Pet,因此它无法获取该值,因为它在类"name"中不存在。List

如果没有看到更多代码,我无法确定。

于 2011-07-27T18:18:59.897 回答