【问题标题】:How to define virtual method with return type which is not void in C#如何定义具有在 C# 中非 void 的返回类型的虚拟方法
【发布时间】:2014-10-23 08:08:40
【问题描述】:

这听起来像是一个愚蠢的问题,但我需要编写一个被继承类覆盖的虚拟方法。我不需要虚拟方法有任何代码,因为这个方法完全依赖于继承的类,因此所有代码都将在覆盖方法中。

但是,该方法的返回类型不是 void。如果我将虚拟方法保持为空,它会给我一个错误“没有所有路径都返回值”。

我想出的唯一解决方案是通过返回一个虚拟的空字符串来实现虚拟方法,但我觉得这不是最好的方法。有没有其他方法可以定义返回类型的虚方法?

编辑:

即使大多数答案在他们自己的方式上都是正确的,但它们对我的情况没有帮助,因此我添加了代码的 sn-ps 来说明为什么我需要创建基类的实例,以及为什么我不能使用接口或抽象:

//base class
public class Parser
{
    public virtual string GetTitle()
    {
        return "";
    }
}

//sub class
public class XYZSite : Parser
{
    public override string GetTitle()
    {
        //do something
        return title;
    }
}

// in my code I am trying to create a dynamic object 
Parser siteObj = new Parser();
string site = "xyz";
switch (site)
{
    case "abc":
       feedUrl = "www.abc.com/rss";
       siteObj = new ABCSite();
       break;
    case "xyz":
       feedUrl = "www.xzy.com/rss";
       siteObj = new XYZSite();
       break;
}
//further work with siteObj, this is why I wanted to initialize it with base class, 
//therefore it won't break no matter what inherited class it was 
siteObj.GetTitle();

我知道我将 Parser 对象转换为 Site 对象的方式似乎不是很理想,但这是它对我有用的唯一方式,所以请随时纠正您在我的代码中发现的任何错误。

编辑(解决方案)

我通过使用接口和抽象遵循了许多回复的建议。但是,只有当我将基类及其所有方法更改为抽象,并从接口继承基类,然后从基类继承子类时,它才对我有用。只有这样我才能确保所有类都有相同的方法,这可以帮助我在运行时生成变体对象。

Public interface IParser
{
    string GetTitle();
}

Public abstract class Parser : IParser
{
    public abstract string GetTitle();
}

Public class XYZ : Parser
{
    public string GetTitle();
    {
        //actual get title code goes here
    }        
}

//in my web form I declare the object as follows
IParser siteObj = null;
...
//depending on a certain condition I cast the object to specific sub class
siteObj = new XYZ();
...
//only now I can use GetTitle method regardless of type of object
siteObj.GetTitle();     

我将功劳归功于 CarbineCoder,因为他付出了足够的努力让我最接近正确的解决方案。不过我感谢大家的贡献。

【问题讨论】:

  • 超类本身不是抽象的。
  • 然而它有一个方法,它本身并没有做任何有用的事情,并且每个重写类都应该重写?听起来是不是应该是抽象的?
  • 我非常感谢它修复了我的代码逻辑,我想问题的根源在于我首先使用继承的方式。请检查上面的代码。
  • 如果"abc" 和"xyz" 详尽(即没有使用其他site 值),那么只需删除变量声明的= new Parser() 部分并将default 添加到您的switch 中,它会抛出NotSupportedException(以使明确的分配分析变得愉快)。现在可以将基类声明为abstract。

标签: c# oop inheritance overriding


【解决方案1】:

你可以抛出 NotImplementedException 而不是返回对象:

    public virtual object Method()
    {
        throw new NotImplementedException();
    }

但是如果你没有在虚拟方法中实现任何东西,你可以创建抽象而不是虚拟:

    public abstract object Method();

编辑:

另一种选择是为其创建接口。

public interface IMethods
{
    object Method();
}

让你的类成为这个接口的子类。

【讨论】:

  • 我无法在非抽象类中定义抽象方法。此外,抛出异常比返回虚拟返回更好吗?
  • 所以让它抽象或使用我上面写的虚拟方法。如果您的虚拟方法必须实现,那么是的,最好抛出异常。
  • 这很有趣,为什么你能告诉我如何更好,我的意思是我只需要让子类调用覆盖的方法,反正我不需要处理异常。
  • 我不确定你需要什么,但我写了你能做什么的选项。
  • 请检查上面的代码,不知道我是否可以进一步解释。
【解决方案2】:

你需要在这里使用abstract。 abstract 修饰符表示被修改的事物有一个缺失或不完整的实现。

public abstract returntype MethodName();

但是正如您所说,“由于此方法完全依赖于继承的类,因此所有代码都将在覆盖方法中”,而不是您真的要覆盖该方法的功能在继承的类中,您为什么要关心该方法是否返回虚拟对象或东西? (例如:您可以将其设为虚拟并开始)

编辑:由于不能将类标记为抽象类,因此可以使用virtual 方法。

public virtual returntype MethodName()
{
   .....
   return xyz;
}

(仅供参考:abstract 成员隐含为virtual。而abstract 类似于pure virtual。所以你需要virtual,而不是pure virtual)

【讨论】:

  • 被覆盖的方法的返回类型为字符串。所以我需要虚拟方法具有相同的返回类型。但是我不需要任何代码行的虚拟方法。
  • @AbuLamar 没错。您现在正处于为y 妥协x 的阶段,反之亦然。如果你真的真的不想要任何实现,那么根据价格,你应该去abstract 类实现。或者您可以妥协并在您的虚拟方法中返回一个假人。毕竟,这就是 virtual 的用途(即通知编译器,如果功能未被覆盖,请使用 virtual )。或其他选项是抽象的;)
  • 我明白你的意思。问题是我陷入了超类不是抽象的情况。我需要从中创建一个对象。此外,超类还有一些未被覆盖的方法。它只是有一些被覆盖的纯虚拟方法。我最终编写的方法如下: public virtual string GetTitle(){ return "";我只是认为会有更好的方法来处理这种情况。
【解决方案3】:

由于其他答案已经讨论了抽象/虚拟实现,我建议我自己的版本。

您的要求存在矛盾。

  1. 您需要一个不是抽象的基类,但它有一个未实现的方法。您不认为这种未实现的方法会使类不完整并最终使其成为抽象类,即使您没有明确表示?
  2. 所以让我们假设您的类永远不会是一个抽象类,将它作为一个普通类是完全合理的。从类中完全删除此方法并将其移至接口是否有意义?

你能不能试着把这个方法提取出来放到一个接口里。

interface NewInterface
{
    string NewMethod();
}

public BaseClass
{
   ...
}

public DerivedClass : BaseClass, NewInterface
{
    public string NewMethod
    {
       ...
    }
}

如果你能做到这一点,那么你不必担心基类是抽象的/有 NotImplemented 异常,唯一的缺点是每个派生类都应该实现这个接口,但这就是使基类非抽象的关键.

我认为为您的方法实现 Abstract BaseClass/ Interface 没有任何问题。两者都应该是解决您问题的方法。

//Parser siteObj = new Parser(); - Dont initialize it here, 
//your are initializing it once more below
NewIterface siteObj; 
string site = "xyz";
switch (site)
{
    case "abc":
       feedUrl = "www.abc.com/rss";
       siteObj = new ABCSite();
       break;
    case "xyz":
       feedUrl = "www.xzy.com/rss";
       siteObj = new XYZSite();
       break;
 }

【讨论】:

  • 这听起来不错,但请检查我的更新,看看为什么我不能使用界面。
  • 我认为你可以使用抽象类/接口。它们非常适合在运行时创建对象 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-14
  • 2014-08-24
  • 2014-11-04
  • 1970-01-01
  • 1970-01-01
  • 2018-12-25
  • 2021-03-02
相关资源
最近更新 更多