例如,我有两个类执行相同的功能:
class HDD : Disk
{
public HDD RMA()
{
HDD newHDD = RMAService.Exchange(this);
return newHDD;
}
}
class SSD : Disk
{
public SSD RMA()
{
SSD newSSD = RMAService.Exchange(this);
return newSSD;
}
}
我想要的是在基类中实现RMA函数,但保持强类型返回值,以便用户可以通过函数签名确定它们正在返回它们发送的磁盘类型!
到目前为止我尝试了什么:
(见下面的解决方案)
但这种类型定义很难看。任何创建自己的Disk类或对磁盘的引用的人都很难知道如何正确使用该类型。
也无法将type参数约束为正在定义的类。奇怪的是,没有一种在基类中声明属性或方法的专门方法,其中编译时类型是派生类型的任何类型。
答案 0 :(得分:1)
发布这个答案来设置一个基线,但正如我所说的,我不是这个奇怪的“让一个类将自己作为其基类的类型参数传递”的粉丝。
abstract class Disk<T> where T : Disk<T> //Ugly recursive type parameter
{
public Disk()
{
if( this.GetType() != typeof(T) ) //Ugly type check
throw new Exception("The type argument must be precisely the " +
"derived class you're defining. Annoying eh?")
}
public T RMA()
{
Disk<T> newDisk = RMAService.Exchange(this)
return (T)newDisk; //Ugly explicit cast
}
}
允许你去:
class HDD : Disk<HDD> { } //Ugly self-referencing type parameter
class SSD : Disk<SSD> { }
HDD newHDD = someHDD.RMA();
答案 1 :(得分:1)
我刚刚使用扩展方法提出了这个解决方案,看起来好多了。有什么理由说它在编译时似乎不起作用?
public abstract class Disk
{
public Disk() { }
}
public static class Disk_Extension_Methods
{
public static T RMA<T>(this T oldDisk) where T : Disk
{
T newDisk = RMAService.Exchange(oldDisk)
return newDisk;
}
}
允许你去:
public class HDD : Disk { }
public class SSD : Disk { }
HDD newHDD = someHDD.RMA();
答案 2 :(得分:1)
您可以使用Disk
构造函数和protected
dynamic
在Exchange
构造函数中使基线解决方案更容易阅读并避免类型检查{1}}致电:
abstract class Disk<T> where T : Disk<T> {
protected Disk()
{
}
public T RMA()
{
return RMAService.Exchange((dynamic)this);
}
}
protected
构造函数使class HDD : Disk<SSD>
这样的类在编译时失败并且dynamic
延迟Exchange
方法重载匹配决策直到运行时,所以你将得到正确的(或者非拟合真this
类型时出错。
答案 3 :(得分:0)
不确定这是否是您想要的,但尝试将基类中的(隐藏)实现与派生子类中的公共接口方法分开。
abstract class Disk //base class
{
protected Disk CreateRMA()
{
Disk newDisk;
newDisk = new RMAService.Exchange(this);
...whatever else needs to be done...
return newDisk;
}
}
class HDD: Disk
{
public HDD RMA()
{
return CreateRMA();
}
}
class SSD: Disk
{
public SSD RMA()
{
return CreateRMA();
}
}
每个派生类的RMA()
方法只调用基类的CreateRMA()
方法,然后将生成的Disk
对象强制转换为派生类类型。每个返回的值都有正确的子类型,每个RMA()
方法的所有实际工作都是在基类方法中完成的。
现在你可以做到这些:
HDD disk1 = someHDD.RMA();
SSD disk2 = someSSD.RMA();
<强>附录强>
这不能解决OP的问题,因为对RMAService.Exchange()
的调用应特定于(重载)每个派生子类型。另一种方法是在派生类型的方法中保持该调用,但允许基类完成所有其他任何需要的初始化工作:
// Second approach
abstract class Disk //base class
{
protected Disk CreateRMA(Disk newDisk)
{
...other initialization code...
return newDisk;
}
public abstract Disk RMA(); //not sure if this works
}
class HDD: Disk
{
public override HDD RMA()
{
return CreateRMA(new RMAService.Exchange(this));
}
}
class SSD: Disk
{
public override SSD RMA()
{
return CreateRMA(new RMAService.Exchange(this));
}
}
对于派生类来说,这是一个更多的工作,但仅适用于重载的new
调用;所有其余的初始化代码都保存在基类方法中。
<强>投降强>
好的,这也行不通,因为C#不支持covariant return types。