将构造函数参数从接口类型强制转换为具体类类型是否错误
本文关键字:类型 错误 是否 转换 参数 构造函数 接口类型 | 更新日期: 2023-09-27 18:04:23
给定如下类:
public interface ISession {}
public class Session : ISession
{
internal Uri ServerUri { get; private set; } // not in interface obviously
}
现在我在同一个项目中有另一个类,它依赖于Session
:
public interface IDataClass {}
internal DataClass : IDataClass
{
private readonly Session _session;
public DataClass(ISession session)
{
_session = (Session) session;
}
// some more methods that access the internal property _session.ServerUri
// and call methods on the session object
// ...
}
实际上Session类非常复杂。为了对DataClass
进行单元测试,我将构造函数参数设置为ISession
,因此我能够模拟依赖关系并验证ISession
模拟上的某些方法调用。
然而,DataClass
中的一些方法必须访问_session.ServerUri
属性,因此字段必须是Session
类型而不是ISession
。
我还可以使字段类型为ISession
,并在每次访问内部属性时强制转换该字段,这将使在这个特定位置更清楚为什么需要具体的internal
类。
每次我以上述方式实现强制类型转换时,我都想知道如果有更好的代码设计,是否可以避免强制类型转换。我经常找到更好的方法来摆脱石膏。
但是上面的例子呢?这是好的代码设计吗?还是有更干净的方法?我只是觉得用上面的方法从构造函数初始化字段很奇怪。
老实说,我认为你目前的系统不是个好主意。
你的构造函数声明"只要它实现了ISession
,我就接受任何东西",但这不是真的真的——调用代码在试图创建DataClass
实例时得到InvalidCastException
时,可能会发现这一点。
ISession
或中声明ServerUri
从ISession
继承的接口-但在任何一种情况下,你需要声明(并存储)这个依赖关系仅在DataClass
你是对的,像这样的强制转换很容易出错,因为编译器没有简单的方法来告诉它会失败。
然而,看起来问题的根源是缺乏对ServerUri
属性的访问,所以您添加了强制转换作为解决方案。如果是这种情况,您应该能够同时拥有它——保留接口,并且可以访问该属性,如果您可以添加一个新接口:
public interface ISessionWithServerUri : ISession { // Come up with a better name
Uri ServerUri {get;}
}
现在您的Session
类可以实现ISessionWithServerUri
,允许您将_session
的声明从Session
类更改为ISessionWithServerUri
接口:
internal DataClass : IDataClass
{
private readonly ISessionWithServerUri _session;
public DataClass(ISessionWithServerUri session)
{
_session = session; // Look, no cast!
}
// some more methods that access the internal property _session.ServerUri
// and call methods on the session object
// ...
}
由于DataClass
依赖于Session
,因此它应该在其构造函数中声明它。该类的任何客户端都应该能够从构造函数中定义的类型/契约创建一个有效的实例。
如果你想依赖于一个接口,那么你应该创建一个包含你需要的成员的新接口,例如
public interface IUriSession : ISession
{
Uri ServerUri { get; }
}
并将构造函数更改为
public DataClass(IUriSession session) { ... }
我会尽量避免像在构造函数中那样的显式类型强制转换。我假设您正在使用IoC容器来解析依赖关系,如果具体类型映射更改为实现该接口的不同类(并且没有该内部属性),这显然会中断。这也有点违背了在该类中使用依赖注入的目的。
你能改变数据类的构造函数注入不同的类型吗?如果是这样,您可以创建一个实现了ISession的接口,并且还包含了ServerUri属性,创建一个实现了新接口的类,然后将该类型注入到构造函数(接口)中。