上铸辅助方法
本文关键字:方法 | 更新日期: 2023-09-27 18:20:14
我有以下类:
class Alpha
{
}
class Beta : Alpha
{
}
class Gamma : Beta
{
}
class Epsilon : Beta
{
}
我有几个方法,我把它们作为参数:
void Receiver(Gamma gamma);
void Receiver(Epsilon epsilon);
void Receiver(Beta beta);
void Receiver(Alpha alpha);
我需要一些不寻常的东西
我希望能够将Alpha对象传递给所有方法,但我不希望像void Receiver(Beta beta);
这样的方法能够接收从Beta
继承的类型的对象(也就是说,如果传递了Gamma
或Epsilon
对象,我最坏的情况下希望引发Exception
。
我如何才能以足够通用的方式最好地实现这一点?
我在想,对于第一部分,我应该有一个允许向上广播的方法,比如
class Alpha
{
public T Upcast<T>() where T : Alpha
{
// somehow return a T
}
}
这里的问题是,我希望它能在所有级别上运行,例如,我也希望能够"升级"Beta
。
第二部分应该更容易,因为我只会抛出传递的对象,这些对象超出了我需要的类型。
这样的东西就足够了:
void Receiver(Epsilon epsilon)
{
// if epsilon inherits from Epsilon, throw.
}
你能帮我解决问题的第一部分吗?谢谢
您似乎在努力处理能够处理给定类型的代码,但不能相信它能够正确处理子类型。一般来说,这违反了许多OOP原则,其中之一是LSP,或Liskov替代原则。
你可能会认为访客模式是克服这个问题的一种手段。它非常接近你已经拥有的,有一些小的修改,这很好!当模式从你的代码中出现,而不是被迫出现时,这很好。
void Receiver
方法本质上已经是访问者实现,所以让我们重命名它们并创建一个接口。
interface IVisitor
{
void Visit(Gamma gamma);
void Visit(Epsilon epsilon);
void Visit(Beta beta);
void Visit(Alpha alpha);
}
处理每个元素类型处理的类只需要实现该接口。
class Visitor : IVisitor
{
public void Visit(Gamma gamma) { Console.WriteLine("Visiting Gamma object"); }
public void Visit(Epsilon epsilon) { Console.WriteLine("Visiting Epsilon object"); }
public void Visit(Beta beta) { Console.WriteLine("Visiting Beta object"); }
public void Visit(Alpha alpha) { Console.WriteLine("Visiting Alpha object"); }
}
然后让每个元素类型也实现一个简单通用的接口
interface IElement { void Accept(IVisitor visitor); }
class Alpha : IElement
{
public virtual void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
class Beta : Alpha
{
public override void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
// etc.
(严格来说,接口不是必需的,它只是一种良好的形式。)
接下来是一个双重调度方法,其中一个元素调用特定于其自身类型的访问者方法,即使您可能通过基类型对其进行了引用。
Alpha alpha = new Beta();
IVisitor visitor = new Visitor();
alpha.Accept(visitor);
如果你已经正确地实现了它,你应该在屏幕上看到"访问Beta对象"(或者,用你的话来说,你应该看到所需的"接收器"行为被执行。)
您可能会考虑的另一个选项是,简单地将Receiver
作为基类上的虚拟方法,并让派生类覆盖它,并在类内具有行为(如果这对您的层次结构有意义的话)。如果行为需要是外部的,您还可以考虑一种工厂方法,它知道如何为给定的类创建特定的处理器。如果将子类型传递给期望基的方法,则有许多选项不会使程序发疯。
我需要一些不寻常的东西。我希望能够通过Alpha对象到所有方法,但我不想要void这样的方法接收器(Beta-Beta);能够接收类型为从Beta继承(也就是说,在最坏的情况下,如果传递Gamma或Epsilon对象。
这确实很奇怪。我不确定你是否真的想要。您似乎已经颠倒了继承层次结构,其中超类型可以替换派生类型,而不是相反,您应该真正地重新思考您正在尝试做什么。
您可以执行GetType并检查它是否是测试版。
我希望能够将Alpha对象传递给的所有方法
你不能可靠地做到这一点。Alpha不是Gamma,因此不能可靠地将其用作接收器(Gamma)的参数。否则你可以这样做:
Alpha a = new Gamma(); // legal
Receiver((Epsilon)a); // not legal
如果你像在问题中那样定义Receiver函数,编译器将根据声明的类型(或者如果你强制类型,则选择强制类型)选择正确的方法:
Epsilon e = new Epsilon();
Alpha a = new Gamma();
Receiver(e); // calls Receiver(Epsilon)
Receiver(a); // calls Receiver(Alpha)
Receiver((Gamma)a); // calls Receiver(Gamma)
Receiver((Beta)e); // calls Receiver(Beta)
因此,如果调用正确,编译器将选择正确的方法。
但我不希望像
void Receiver(Beta beta);
这样的方法能够接收从Beta 继承的类型的对象
那么您没有正确使用继承。Gamma
是一个Beta
。为什么要阻止继承的类型使用该方法?如果您希望Gamma和Beta在没有继承的情况下共享一些属性/方法,请选择另一种模式,如封装或组合并使用接口。
也就是说,你的Upcast功能应该很简单:
public T Upcast<T>() where T : Alpha
{
return this as T; // will return null is this is not a T
}
...
new Beta().Upcast<Gamma>(); // will return null
new Epsilon().Upcate<Epsilon>(); // will return the Epsilon