- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
背景
在 Asp.Net Core 中使用 MVC,我正在使用 Controller -> 服务 -> View 模型 -> View 方法。
我想要 2 个服务共享一些基础数据和功能。
我的要求是一个实体由 2 种不同的用户类型共享。 IE。管理员用户和标准用户。
管理员用户将有权访问其他属性(在 View 模型中定义)和功能(在服务中定义),而标准用户则不能。
在下面的示例代码中,Foo1 相当于管理员,Foo2 是标准用户。
Controller 操作
private readonly IFoo1Service _foo1Service;
private readonly IFoo2Service _foo2Service;
public HomeController
(IFoo1Service foo1Service,
IFoo2Service foo2Service)
{
_foo1Service = foo1Service;
_foo2Service = foo2Service;
}
public IActionResult Foo1()
{
Foo1ViewModel vm = _foo1Service.NewViewModel();
return View(vm);
}
public IActionResult Foo2()
{
Foo2ViewModel vm = _foo2Service.NewViewModel();
return View(vm);
}
服务
public class Foo1Service : BaseFooService, IFoo1Service
{
public Foo1ViewModel NewViewModel()
{
//*** LINE CAUSING THE ERROR ***
//NewBaseFooViewModel returns a BaseFooViewModel
//AS Foo1ViewModel derives from the BaseFooViewModel
//I thought I could cast it
Foo1ViewModel vm = (Foo1ViewModel) NewBaseFooViewModel();
//set some defaults
vm.Foo1Field1 = "Foo1Field1";
vm.Foo1Field2 = "Foo1Field2";
return vm;
}
public Foo1ViewModel GetViewModelFromEntity(Entity entity)
{
Foo1ViewModel vm = (Foo1ViewModel) GetBaseFooViewModelFromEntity(entity);
vm.Foo1Field1 = entity.Foo1Field1;
vm.Foo1Field2 = entity.Foo1Field2;
return vm;
}
}
public class Foo2Service : BaseFooService, IFoo2Service
{
public Foo2ViewModel NewViewModel()
{
Foo2ViewModel vm = (Foo2ViewModel) NewBaseFooViewModel();
return vm;
}
public Foo2ViewModel GetViewModelFromEntity(Entity entity)
{
Foo2ViewModel vm = (Foo2ViewModel) GetBaseFooViewModelFromEntity(entity);
return vm;
}
}
public class BaseFooService : IBaseFooService
{
public BaseFooViewModel NewBaseFooViewModel()
{
return new BaseFooViewModel()
{
BaseFooField1 = "BaseFooField1",
BaseFooField2 = "BaseFooField2",
BaseFooField3 = "BaseFooField3"
};
}
public BaseFooViewModel GetBaseFooViewModelFromEntity(Entity entity)
{
return new BaseFooViewModel()
{
BaseFooField1 = entity.BaseFooField1,
BaseFooField2 = entity.BaseFooField2,
BaseFooField3 = entity.BaseFooField3
};
}
}
接口(interface)
public interface IFoo1Service : IBaseFooService
{
Foo1ViewModel NewViewModel();
}
public interface IFoo2Service : IBaseFooService
{
Foo2ViewModel NewViewModel();
}
public interface IBaseFooService
{
BaseFooViewModel NewBaseFooViewModel();
}
查看模型
public class Foo1ViewModel : BaseFooViewModel
{
public string Foo1Field1 { get; set; }
public string Foo1Field2 { get; set; }
}
public class Foo2ViewModel : BaseFooViewModel
{
}
public class BaseFooViewModel
{
public string BaseFooField1 { get; set; }
public string BaseFooField2 { get; set; }
public string BaseFooField3 { get; set; }
}
观看次数
Foo1
@model BaseServiceSample.ViewModels.Foo.Foo1ViewModel
<h1>Base foo fields</h1>
<p>@Model.BaseFooField1</p>
<p>@Model.BaseFooField2</p>
<p>@Model.BaseFooField3</p>
<h2>Foo1 fields</h2>
<p>@Model.Foo1Field1</p>
<p>@Model.Foo1Field2</p>
Foo2
@model BaseServiceSample.ViewModels.Foo.Foo2ViewModel
<h1>Base foo fields</h1>
<p>@Model.BaseFooField1</p>
<p>@Model.BaseFooField2</p>
<p>@Model.BaseFooField3</p>
启动时的依赖注入(inject)
services.AddScoped<IFoo1Service, Foo1Service>();
services.AddScoped<IFoo2Service, Foo2Service>();
问题
应用程序编译正常,但在运行时出现错误:
InvalidCastException: Unable to cast object of type 'BaseServiceSample.ViewModels.Foo.BaseFooViewModel' to type 'BaseServiceSample.ViewModels.Foo.Foo1ViewModel'
请参阅我在 Foo1Service 中的评论,这些评论位于导致运行时错误的代码行上方。
我认为,如果一个类派生自基类,则它可以转换为派生类,但我可能将其与 MVC 中模型绑定(bind)的工作方式混淆了。
问题
我如何更改我的代码,使其支持管理两个不同用户组的共享属性和功能的基本 View 模型和基本服务的基本要求,但允许用户组扩展这些属性/功能?
根据我的研究,我可能需要使用抽象类或类型参数,但我无法让它工作。
我在没有尝试提供类型参数的情况下包含了代码示例,以保持代码更简单,并希望有人更容易指导我在哪里需要使用它。
对于类型参数,我的意思是:
BaseFooService<T> : IBaseFooService<T> where T : class
最佳答案
问题是:
public Foo2ViewModel GetViewModelFromEntity(Entity entity)
{
Foo2ViewModel vm = (Foo2ViewModel) GetBaseFooViewModelFromEntity(entity);
return vm;
}
public BaseFooViewModel GetBaseFooViewModelFromEntity(Entity entity)
{
return new BaseFooViewModel()
{
BaseFooField1 = entity.BaseFooField1,
BaseFooField2 = entity.BaseFooField2,
BaseFooField3 = entity.BaseFooField3
};
}
GetBaseFooViewModelFromEntity
返回一个新的 BaseFooViewModel
。它不返回 Foo2ViewModel
。您可以将 Foo2ViewModel
转换为其基类,但反之则不行。
I thought that if a class derived from a base class that it could be casted as the derived class
您不能将基类的任何对象强制转换为任何派生类型。仅当对象实际上是该派生类型(或从派生类型派生的东西)时,转换才有效。
换句话说,您不能这样做,因为 BaseFooViewModel
不是 Foo2ViewModel
:
var model = new BaseFooViewModel();
var fooModel = (Foo2ViewModel)model;
但您可以这样做,因为 Foo2ViewModel
始终是 BaseFooViewModel
:
var fooModel = new Foo2ViewModel();
var model = (BaseFooViewModel)fooModel;
你可以这样做(但你为什么要这么做?)
Foo2ViewModel fooModel = new Foo2ViewModel();
BaseFooViewModel model = (BaseFooViewModel)fooModel;
Foo2ViewModel thisWorks = (Foo2ViewModel)model;
之所以有效,是因为该对象始终是一个 Foo2ViewModel
,因此它可以转换为该对象或其基类型。
这里有一个让编译器引导你的建议,这样你就会得到编译器错误而不是运行时错误。这将以更多编译器错误的形式打开一堆蠕虫,但好消息是您可以在不运行代码的情况下修复它们。编译器错误比运行时错误好。
第一步是将 BaseFooModel
抽象化,这样您就无法创建它的实例。大概您只想处理像 Foo1ViewModel
、Foo2ViewModel
这样的类。使基类抽象将确保您只能创建派生类。
public abstract class BaseFooViewModel // Just added "abstract"
{
public string BaseFooField1 { get; set; }
public string BaseFooField2 { get; set; }
public string BaseFooField3 { get; set; }
}
当你使 BaseFooModel
抽象时,这将无法编译:
new BaseFooViewModel()
...因为您无法创建抽象类的实例。您只能创建非抽象派生类的实例。
假设您的派生类没有带参数的构造函数,您可以这样做:
public TFooModel GetBaseFooViewModelFromEntity<TFooModel>(Entity entity)
where TFooModel : BaseFooViewModel, new()
{
return new TFooModel()
{
BaseFooField1 = entity.BaseFooField1,
BaseFooField2 = entity.BaseFooField2,
BaseFooField3 = entity.BaseFooField3
};
}
现在您要告诉方法要创建哪个特定的继承类。通用约束 - BaseFooViewModel, new()
- 指定它必须继承自 BaseFooViewModel
,并且它必须具有默认构造函数,以便该类可以创建它的新实例.
它将创建您指定的类的一个实例,但因为它"is"一个 BaseFooViewModel
,所以它可以设置属于该基类的属性。
然后你可以这样调用方法:
Foo2ViewModel vm = GetBaseFooViewModelFromEntity<Foo2ViewModel>(entity);
另一种看待它的方式。像这样的运行时转换:
Foo2ViewModel vm = (Foo2ViewModel) GetBaseFooViewModelFromEntity(entity);
通常要避免。我说一般是因为有很多异常(exception)。但是在编写我们自己的泛型类时,我什至会说我们应该始终避免它。相反,最好编写代码,以便我们拥有的声明类型是我们唯一关心的类型。
换句话说,如果方法返回 Foo
或参数是 Foo
类型,那么我们唯一关心的类型是 Foo
。我们不关心它的基类,也不关心我们得到的对象是否真的是继承自Foo
的东西。
这里有一篇单独的文章,稍微描述一下我的个人经历。我称之为 Generic Rabbit Hole of Madness .
关于c# - 我如何在 MVC 中跨我的 View 模型和服务使用基类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55021535/
在我的应用程序中播放背景音乐时遇到问题。 首先,我在第一个 Storyboard View Controller 中的 ViewDidLoad 方法中开始播放音乐。即使我从一个页面跳转到另一个页面,它
我想跨行连接数组,然后进行不同的计数。理想情况下,这会起作用: WITH test AS ( SELECT DATE('2018-01-01') as date, 2 as value,
这是一个场景: Repo A 是一个包含大量模块和依赖项的怪异代码。安装起来并不容易。它由其他人维护并托管在 Github 上。 Repo A 包含一个非常有用的模块 X,并且几乎不依赖于 Repo
目前,我在一台服务器上运行了一个应用程序。有一个 crontab 设置,因此根据指定的规则,在某些时间运行任务。 现在,我正在考虑将我的应用程序迁移到 docker 容器中,以便我能够独立运行我的应用
我有一个全局表,我想在两个不同的 Lua 状态之间保持同步。根据我所阅读和理解的内容,唯一的方法似乎是,在我的 C 后端,在状态之间进行表的深层复制(如果表已被修改)。有没有更好的办法 ? 另外,我看
我们目前有一个 asmx webservice,它公开了一个方法来对 Sql 数据库进行各种更新,内部包装在 SqlTransaction 中。 我正在 WCF 中重写此服务,我们希望将现有方法拆分为
我是 Qt 的新手,所以请原谅这个问题的简单性,但我对 Qt 线程有点困惑。假设我有 3 个线程:主要的默认 GUI 线程和我自己创建的 2 个线程(称为 WorkerThread)。我的每个 Wor
我们的产品有一个 Restful API 和一个服务器渲染的应用程序(CMS)。两者共享数据库。两者都是用django编写的 两者所需的字段和模型并不是相互排斥的,有些仅针对 API,有些针对 CMS
我正在实现一个基于角色的访问控制系统,它具有以下数据库表。 groups --------- id (PK) name level resources --------- id (PK) name r
我有三个应用程序,为了便于管理,我希望将它们分开。他们按照建议作为 Plack 服务器运行 here , 代理在 nginx 后面。 我想有一个单独的应用程序来管理登录,并在所有其他应用程序之间共享该
我的主窗口上有一个 UIWebView。我可以通过我的第二个 View Controller 来控制它吗?如果可以的话你能给我举个例子吗? 最佳答案 是的,你可以。 “如何”是一个基本的 Cocoa/
我想制作一个小型应用程序,从连接到串行端口的设备收集数据,并将其通过 LAN 传递到另一个应用程序,后者将其存储在数据库中。 我已经在一台 PC 上的一个应用程序中完成了此操作,因此实际上会将应用程序
从主 AppDomain,我试图调用在不同 AppDomain 中实例化的类型中定义的异步方法。 比如下面的类型MyClass继承自 MarshalByRefObject并在新的 AppDomain
因为 LiveServerTestCase继承自 TransactionTestCase ,默认行为是在每个测试方法结束时删除测试数据。我想用LiveServerTestCase类,但保留方法之间的测
我正在开发我的第一个 WPF/MVVM 应用程序,但我在命令知识方面遇到了限制! 这是我的场景。 我有一个窗口——Customer.xaml。 它包含 2 个用户控件 查看CustomerSearch
这是我的 WPF 应用程序模型的简化版本: Employee +Name:string Client +Name:string +PhoneNumber:string Appointmen
我有一个 mercurial 存储库,它使用子存储库功能(如 .hgsub 文件中定义的)引入依赖项,但我正在努力让它在 TeamCity 中工作。 我启用了 mercurial_keyring 扩展
我正在尝试使用新的 Azure 虚拟网络公共(public)预览版的对等互连功能来加入我在两个不同订阅(即不同租户)上拥有的两个网络。这可能吗?我没有看到任何其他说法,但是当我尝试在 PowerShe
我有 2 个存储库。由于主干代码位于一个 protected 存储库中,因此我进行了 checkout ,然后 checkin 到另一个存储库(因为用户没有第一个 protected 存储库的权限)。
我有一个项目,其调用结构与此类似: 主要项目/应用 我的图书馆代码 别人的库代码 我的图书馆代码 一切都是用 C# 编写的,我可以访问“其他人的库代码”。他们的代码不包含在我的项目中,因为它是开源的而
我是一名优秀的程序员,十分优秀!