抽象类可以作为控制器动作的参数吗?
我在Controller中有一个Action函数,它是用AJAX调用的。 该行动涉及1个参数。 客户端,我构造了一个JSON对象,应该序列化为该1参数。 我遇到的问题是参数类被声明为abstract。 因此,它无法实例化。
当AJAX点击该Action时,我得到以下内容:
无法创建抽象类。
堆栈跟踪:
[MissingMethodException:无法创建抽象类。]
System.RuntimeTypeHandle.CreateInstance(RuntimeType类型,Boolean publicOnly,Boolean noCheck,Boolean&canBeCached,RuntimeMethodHandleInternal&ctor,Boolean&bNeedSecurityCheck)+0
System.RuntimeType.CreateInstanceSlow(Boolean publicOnly,Boolean skipCheckThis,Boolean fillCache)+98
System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly,Boolean skipVisibilityChecks,Boolean skipCheckThis,Boolean fillCache)+241 System.Activator.CreateInstance(Type type,Boolean nonPublic)+69 ……………
有没有办法在不创建不同参数对象的情况下实现这样的场景,“取消声明”参数对象为抽象,或者深入研究MVC的机制?
更新
我目前正在与后端开发人员一起调整他们的对象。 无论哪种方式,我认为这将是最终的解决方案。 谢谢大家的答案。
更新:示例现在使用AJAX JSON POST
如果必须使用抽象类型,则可以提供自定义模型绑定器来创建具体实例。 一个例子如下所示:
型号/型号粘合剂
public abstract class Student { public abstract int Age { get; set; } public abstract string Name { get; set; } } public class GoodStudent : Student { public override int Age { get; set; } public override string Name { get; set; } } public class BadStudent : Student { public override int Age { get; set; } public override string Name { get; set; } } public class StudentBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var values = (ValueProviderCollection) bindingContext.ValueProvider; var age = (int) values.GetValue("Age").ConvertTo(typeof (int)); var name = (string) values.GetValue("Name").ConvertTo(typeof(string)); return age > 10 ? (Student) new GoodStudent { Age = age, Name = name } : new BadStudent { Age = age, Name = name }; } }
控制器动作
public ActionResult Index() { return View(new GoodStudent { Age = 13, Name = "John Smith" }); } [HttpPost] public ActionResult Index(Student student) { return View(student); }
视图
@model AbstractTest.Models.Student @using (Html.BeginForm()) { Age @Html.TextBoxFor(m => m.Age)
Name @Html.TextBoxFor(m => m.Name)
}
添加到Global.asax.cs
protected void Application_Start() { ... ModelBinders.Binders.Add(new KeyValuePair(typeof(Student), new StudentBinder())); }
框架无法知道您想要的具体实现,也不会承担此类决策的责任。 所以你有两种可能性:
- 使用具体类型作为操作参数
- 为这个抽象类编写一个自定义模型绑定器,它基于一些请求参数将返回一个特定的实例。
您将不得不创建抽象类的子类并将其传递给它。 从根本上说,抽象类不允许自己实例化。 但是,如果你有一个C#方法,如:
protected void Foo(MyAbstractClass param1)
…然后你仍然可以传递Foo一个派生自MyAbstractClass的类型的实例。 因此,您可以创建一个具体的子类MyChildClass : MyAbstractClass
并将其传递给您的方法,它应该仍然有效。 您不必更改Foo
方法,但您需要访问C#代码,以便创建MyChildClass
。
如果您正在使用generics – 例如,如果您的方法签名是:
protected void Foo(IEnumerable param1)
…然后它变得更加复杂,你会想要研究C#generics中的协方差和逆变 。
如果您有权访问控制器,您可以添加另一个inheritance抽象类的类而不指定任何成员,并使用它来序列化反序列化,然后将其基础返回到另一个层吗?
我知道这不是一个好习惯,但有些黑客但我不知道抽象类是否可以某种方式序列化。
不 – 试图将JSON反序列化为抽象类的对象是没有意义的。 你能不能成为一个合适的class级?