C# 抽象类可以是控制器';什么行动?

C# 抽象类可以是控制器';什么行动?,c#,ajax,serialization,asp.net-mvc-3,C#,Ajax,Serialization,Asp.net Mvc 3,我在控制器中有一个Action函数,它是用AJAX调用的。该操作在1个参数中执行。在客户端,我构造了一个JSON对象,该对象应序列化为该1参数。我遇到的问题是参数类被声明为抽象类。因此,它不能被实例化 当AJAX执行该操作时,我会得到以下结果: 无法创建抽象类 堆栈跟踪: [MissingMethodException:无法创建 抽象类。] System.RuntimeTypeHandle.CreateInstance(RuntimeType 类型,仅布尔型,布尔型 noCheck、Boolea

我在控制器中有一个Action函数,它是用AJAX调用的。该操作在1个参数中执行。在客户端,我构造了一个JSON对象,该对象应序列化为该1参数。我遇到的问题是参数类被声明为抽象类。因此,它不能被实例化

当AJAX执行该操作时,我会得到以下结果:

无法创建抽象类

堆栈跟踪:

[MissingMethodException:无法创建 抽象类。]
System.RuntimeTypeHandle.CreateInstance(RuntimeType 类型,仅布尔型,布尔型 noCheck、Boolean和canBeCached, RuntimeMethodHandleInternal&ctor, 布尔值&bNeedSecurityCheck)+0
System.RuntimeType.CreateInstanceSlow(布尔值 publicOnly,布尔skipCheckThis, 布尔fillCache)+98
System.RuntimeType.CreateInstanceDefaultCtor(布尔值 publicOnly,Boolean skipVisibilityChecks,布尔型 skipCheckThis,布尔fillCache)+241 System.Activator.CreateInstance(类型 类型,布尔非公共)+69

有没有办法在不创建不同的参数对象、“取消声明”参数对象为抽象对象或深入研究MVC机制的情况下实现这种场景

更新
我目前正在与后端开发人员一起调整他们的对象。无论如何,我认为这将是最终的解决办法。谢谢大家的回答。

没有-尝试将JSON反序列化为抽象类的对象毫无意义。你不能把它变成一个合适的类吗?

你必须创建一个抽象类的子类并传递它。抽象类基本上不允许自己实例化。但是,如果您有一个C#方法,如:

protected void Foo(MyAbstractClass param1)
…然后您仍然可以向Foo传递从MyAbstractClass派生的类型的实例。因此,您可以创建一个具体的子类
MyChildClass:MyAbstractClass
,并将其传递给您的方法,它应该仍然可以工作。您不必更改
Foo
方法,但需要对C代码进行一些访问,以便创建
MyChildClass

如果您使用泛型——例如,如果您的方法签名是:

protected void Foo(IEnumerable<MyAbstractClass> param1)
受保护的void Foo(IEnumerable参数1)

…然后它会变得更复杂,您需要在C#泛型中进行研究。

框架无法知道您需要哪种具体的实现,也不会承担此类决策的责任。这里有两种可能性:

  • 使用具体类型作为动作参数
  • 为这个抽象类编写一个自定义模型绑定器,它基于一些请求参数将返回一个特定实例

  • 如果您有权访问控制器,是否可以添加另一个继承抽象类而不指定任何成员的类,并使用该类序列化反序列化,然后将其基返回到另一层


    我知道这不是一个好的实践,但是有些黑客攻击,但是我不知道抽象类是否可以以某种方式序列化。

    更新:示例现在使用了一个AJAX JSON帖子

    如果必须使用抽象类型,则可以提供用于创建具体实例的。示例如下所示:

    模型/模型活页夹

    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);
    }
    
    protected void Application_Start()
    {
        ...
        ModelBinders.Binders.Add(new KeyValuePair<Type, IModelBinder>(typeof(Student), new StudentBinder()));
    }
    
    查看

    @model AbstractTest.Models.Student
    
    @using (Html.BeginForm())
    {
        <div id="StudentEditor">
            <p>Age @Html.TextBoxFor(m => m.Age)</p>
            <p>Name @Html.TextBoxFor(m => m.Name)</p>
            <p><input type="button" value="Save" id="Save" /></p>
        </div>
    }
    
    <script type="text/javascript">
        $('document').ready(function () {
            $('input#Save').click(function () {
                $.ajax({
                    url: '@Ajax.JavaScriptStringEncode(Url.Action("Index"))',
                    type: 'POST',
                    data: GetStudentJsonData($('div#StudentEditor')),
                    contentType: 'application/json; charset=utf-8',
                    success: function (data, status, jqxhr) { window.location.href = '@Url.Action("Index")'; }
                });
            });
        });
    
        var GetStudentJsonData = function ($container) {
                 return JSON.stringify({
                     'Age': $container.find('input#Age').attr('value'),
                     'Name': $container.find('input#Name').attr('value')
                 });
             };
    </script>
    
    @model AbstractTest.Models.Student
    @使用(Html.BeginForm())
    {
    Age@Html.TextBoxFor(m=>m.Age)

    Name@Html.TextBoxFor(m=>m.Name)

    } $('document').ready(函数(){ $('input#Save')。单击(函数(){ $.ajax({ url:“@Ajax.JavaScriptStringEncode(url.Action(“Index”))”, 键入:“POST”, 数据:GetStudentJsonData($('div#StudentEditor')), contentType:'application/json;charset=utf-8', 成功:函数(数据、状态、jqxhr){window.location.href='@Url.Action(“Index”);} }); }); }); var GetStudentJsonData=函数($container){ 返回JSON.stringify({ 'Age':$container.find('input#Age').attr('value'), 'Name':$container.find('input#Name').attr('value')) }); };
    添加到Global.asax.cs

    public ActionResult Index()
    {
        return View(new GoodStudent { Age = 13, Name = "John Smith" });
    }
    [HttpPost]
    public ActionResult Index(Student student)
    {
        return View(student);
    }
    
    protected void Application_Start()
    {
        ...
        ModelBinders.Binders.Add(new KeyValuePair<Type, IModelBinder>(typeof(Student), new StudentBinder()));
    }
    
    受保护的无效应用程序\u Start()
    {
    ...
    添加(新的键值对(typeof(Student),newstudentbinder());
    }
    
    我认为参数必须是一个具体类型。不允许使用抽象类型或接口类型。这些对象来自应用程序中的另一层,它们几乎都是给我的。我对他们没有任何权力。所以,我想我应该创建自己的对象,然后用自己的数据填充抽象对象:(@Dimskiy-你可以从抽象对象继承你的类。正是我所想的,所以我或多或少写了一个重复的答案,但是+1:)我实际上有一个列表,是的,我确实可以访问C#,但只在我的MVC项目内部。我不能触摸业务/DAL层。@Dimskiy-在这种情况下,您可能仍然能够传入一个
    列表
    ,其中填充了
    ThatDerivedClass
    对象。如果方法允许协方差,您可以传入
    列表
    ,但我不确定。如果您可以编写一个C#包装器来捕获JSON数据,并在将其发送到您的业务/DAL层之前对其进行重新打包,那就太好了。无论谁否决了这一点,请解释原因。我已经阅读并重新阅读了它,我看不出它有什么不正确的原因。这很好,帮助我解决了一个难题。感谢您建议ModelBinders.Binders.Add-in应用程序_Start()。