c#抽象类——“非此即彼”备用功能
本文关键字:非此即彼 功能 备用 抽象类 | 更新日期: 2023-09-27 17:51:21
这里有一个,我有一个这样的抽象类…
public abstract class SpaceshipManager
{
...
public abstract void BuildWith(ParseObject po);
// "Or ..."
public abstract void BuildWith(string label);
...
}
的意义是,派生类必须实现BuildWith一个ParseObject, "OR",他们可以实现BuildWith使用字符串。
现在,我只是做这个…
public abstract void BuildWith(object data);
这很好,但是有更好的方法吗?
从另一个角度来看,你可以有两个方法BuildKeidranType()
BuildBastionType()
这个概念是派生类必须至少实现这些中的一个。
c#中有这样的东西吗?
可以使用泛型:
public abstract class SpaceshipManager<T>
{
public abstract void BuildWith(T source);
}
public class StringBuilderSpaceshipManager : SpaceshipManager<ParseObject> { ... }
c#中没有这样的东西。Generics
可以给你一条出路。但是看到你是从MonoBehavior
衍生出来的,我假设你正在使用的是Unity
,那里有约束,比如类名必须与文件名等相同,这些约束不会给通用行为太多的选择。所以要避免泛型类,关注泛型方法。
下面是一个非常粗糙的例子,使用泛型只是为了好玩,可能不会比你现在的例子好多少,你把参数作为一个对象。然而,这里是:
public abstract class SpaceshipManager: MonoBehaviour
{
public void BuildWith<T>(T po)
{
if (ValidateBuildParam<T>())
{
Build<T>(po);
}
}
protected abstract bool ValidateBuildParam<T>();
protected abstract void Build<T>(T type);
}
public class DerivedA : SpaceshipManager
{
protected override void Build<T>(T po)
{
//Build here
}
protected override bool ValidateBuildParam<T>()
{
return (typeof(T) != typeof(ParseObject)) ? false : true;
}
}
public class DerivedB : SpaceshipManager
{
protected override void Build<T>(T po)
{
//Build here
}
protected override bool ValidateBuildParam<T>()
{
return (typeof(T) != typeof(string)) ? false : true;
}
}
现在有一些缺点,像下面的用法是不正确的:
SpaceshipManager spMan = new DerivedA();
spMan.BuildWith<int>(5);
这将编译和运行,但不会构建任何东西。因此,如果您更改BuildWith的返回类型,如果验证失败或bool true
或false
不,没有这种事。
如果派生类只实现了其中一个重载,调用者如何知道实现了哪个重载?
不,你所要求的这些东西在c#中是不可用的。c#中有接口,但是你必须在派生类中实现所有的方法,因为如果你实现其中一个调用者会感到困惑。
正如其他人已经告诉您的那样,您不能将抽象方法定义为可选的以某种方式实现。
如果可能的话,我建议定义某种通用类型,可以作为BuildWith
方法的输入。例如,label
字符串也可以表示为ParseObject
吗?如果不是,你能想到这两者的一些共同的抽象吗?
如果这两个问题的答案都是否定的,那么我认为这两个方法从一开始就不应该重载。
如果答案是肯定的,那么您只能将以下方法中的一个设置为抽象方法:
public abstract class SpaceshipManager : MonoBehaviour
{
public abstract void BuildWith(ParseObject po);
public void BuildWith(string label)
{
// Static method or constructor here to represent label as a ParseObject.
BuildWith(ParseObject.FromLabel(label))
}
}
在本例中,ParseObject是公共抽象。但是,它也可以是另一个类或接口。
根据具体情况,@Lee发布的泛型选项也可能是一个很好的解决方案,也许与非泛型基类型相结合:
abstract class SpaceshipManager<T> : SpaceshipManager
{
public abstract void BuildWith(T source);
}
abstract class SpaceshipManager
{
// Other methods here
}
如果这两种解决方案都不适合您,您可以将方法改为虚方法,并在需要时重写该行为,但这种设计在您的情况下是否有意义有点令人怀疑。
可以实现两个接口。IBuildWithFromString
和IBuildWithFromParseObject
。然后,您可以通过尝试转换到该接口来查询哪个接口被实现,如果成功,您可以调用适当的方法。