c#抽象类 - "一个或另一个"备用功能

时间:2014-03-22 06:30:32

标签: c# abstract-class

这是一个,我有一个像这样的抽象类...

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

6 个答案:

答案 0 :(得分:3)

您可以使用泛型:

public abstract class SpaceshipManager<T>
{
    public abstract void BuildWith(T source);
}

public class StringBuilderSpaceshipManager : SpaceshipManager<ParseObject> { ... }

答案 1 :(得分:2)

在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

答案 2 :(得分:1)

不,没有这样的事情。

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

答案 3 :(得分:1)

不,你要问的这些东西在c#中没有。在c#中有接口,但你必须在派生类中实现所有方法,因为如果你实现其中一个调用者会感到困惑。

答案 4 :(得分:0)

正如其他人已经告诉过你的那样,你不能将抽象方法定义为可选的以某种方式实现。

如果可能,我建议定义一些可以作为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
}

如果这些解决方案都不适合您,您可以随时将方法设为虚拟,并在需要时覆盖该行为,但这种设计在您的情况下有意义,这有点令人怀疑。

答案 5 :(得分:0)

您可以实现两个接口。 IBuildWithFromStringIBuildWithFromParseObject。然后,您可以通过尝试强制转换到此接口来查询实现哪个接口,如果成功,您可以调用相应的方法。