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#中有这样的东西吗?

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 truefalse

返回null,那将是很好的

不,没有这种事。

如果派生类只实现了其中一个重载,调用者如何知道实现了哪个重载?

不,你所要求的这些东西在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
}

如果这两种解决方案都不适合您,您可以将方法改为虚方法,并在需要时重写该行为,但这种设计在您的情况下是否有意义有点令人怀疑。

可以实现两个接口。IBuildWithFromStringIBuildWithFromParseObject。然后,您可以通过尝试转换到该接口来查询哪个接口被实现,如果成功,您可以调用适当的方法。