C#虚拟&;覆盖关键字

本文关键字:覆盖 关键字 amp 虚拟 | 更新日期: 2023-09-27 18:25:28

我以为我已经搞定了,然后我去查看工作中的一些来源,想知道为什么我从msdn中读到的内容和我在来源中看到的内容有这么多矛盾。。。。

我的理解是virtual关键字可以在方法声明中使用,以允许任何派生类覆盖它

实现超类的虚拟方法时,需要在派生类中使用override关键字。。。。

例如:

public abstract class A
{
    public virtual string GetName();
}

public class B:A
{
    //assume there are some defined properties.
    public override string GetName()
    {
        return FirstName;
    }
}

我有几个问题:

1) 如果一个方法没有实现,那么真的有必要将其定义为虚拟方法吗?当然,它可以在子类中被覆盖,而不需要使用虚拟和覆盖吗?

2) 如果(1)不正确,我认为每个虚拟方法都必须在使用它的子类中重写,这是对的吗…

编辑:

你是对的,我的代码不会编译。。。我想知道为什么。。。。我理解你的答案,但后来我看到了这个:

public abstract class RequestHandler<TRequest, TResponse> : RequestHandler, IRequestHandler<TRequest>, IRequestHandler, IDisposable, ITypedRequestHandler
    where TRequest : global::Agatha.Common.Request
    where TResponse : global::Agatha.Common.Response, new()
{
    protected RequestHandler();
    public virtual void AfterHandle(TRequest request);
    public virtual void BeforeHandle(TRequest request);
    public override Response CreateDefaultResponse();
    public TResponse CreateTypedResponse();
    public override Response Handle(Request request);
    public abstract Response Handle(TRequest request);
}

以上内容不会引起编译器的抱怨。。。

C#虚拟&;覆盖关键字

首先,上述代码无效。虚拟方法仍然必须有一个带有默认实现的主体。要执行上面所做的操作,您需要使用abstract关键字而不是virtual。

abstract意味着没有提供方法体,但从它派生的任何类都必须实现此方法(除非它也是抽象的)。

我认为这基本上回答了你的问题。。。。

  1. 如果它没有实现,那么它就不能是虚拟的,它必须是抽象的。如果它有一个什么都不做的实现,那么就必须实现它。

  2. 虚拟类的全部意义在于它有默认行为,所以你可以选择是否覆盖它。如果它是抽象的,那么你就必须覆盖它(除非你派生了另一个抽象类)。

如果一个方法没有实现,那么真的有必要将其定义为虚拟方法吗?

您可以使该方法抽象化(它将隐式地使其虚拟化)。

当然,它可以在子类中被覆盖,而不需要使用虚拟和覆盖吗?

如果您只是"覆盖"它而不显式覆盖它,它将不是同一个方法,并且在基类的变量上调用该方法将不会调用派生方法

一个例子会让它变得更清楚:

class B
{
    public virtual void M() { Console.WriteLine("B.M") };
}
class D1 : Base
{
    // Hides the base method
    public new void M() { Console.WriteLine("D1.M") };
}

class D2 : Base
{
    // Overrides the base method
    public override void M() { Console.WriteLine("D2.M") };
}
...
D1 d1 = new D1();
d1.M(); // Prints "D1.M"
B b1 = d1;
b1.M(); // Prints "B.M", because D1.M doesn't override B.M
D2 d2 = new D1();
d2.M(); // Prints "D2.M"
B b2 = d2;
b2.M(); // Also prints "D2.M", because D2.M overrides B.M

如果(1)不正确,我认为每个虚拟方法都必须在使用它的子类中重写,这是对的吗…

不,只有当它是抽象的。。。虚拟方法可以有一个实现,在这种情况下,派生类不必重写它。

1) 如果一个方法没有实现,那么真的有必要将其定义为虚拟方法吗?当然,它可以在子类中被覆盖,而不需要使用虚拟和覆盖吗?

正如在其他答案中所说,virtual方法需要有实现。你把它和abstract搞混了。

如果您询问确实有实现的virtual方法是否需要声明为virtual:在C#中,是的,这是必要的。在Java中,您可以覆盖任何旧方法。C#的设计决定要求用virtual关键字特别允许重写,这样,除非程序员有意,否则方法就不能被重写。

如果程序员没有通过不使用virtual来表达意图,您仍然可以使用new关键字"覆盖"方法。然而,这有点不同。希望这段代码将有助于说明这个概念:

class Program
{
    static void Main(string[] args)
    {
        var baseC = new BaseClass();
        var extC = new ExtClass();
        var lazyC = new LazyClass();
        Console.WriteLine(baseC.NewMethod());
        Console.WriteLine(baseC.VirtualOverrideMethod());
        Console.WriteLine("---");
        Console.WriteLine(extC.NewMethod());
        Console.WriteLine(extC.VirtualOverrideMethod());
        Console.WriteLine("---");
        Console.WriteLine(((BaseClass) extC).NewMethod());
        Console.WriteLine(((BaseClass) extC).VirtualOverrideMethod()); // Redundant typecast
        Console.WriteLine("---");
        Console.WriteLine(lazyC.VirtualOverrideMethod());
        Console.ReadKey();
    }
    public class BaseClass
    {
        public BaseClass()
        {
        }
        public string NewMethod()
        {
            return "NewMethod of BaseClass";
        }
        public virtual string VirtualOverrideMethod()
        {
            return "VirtualOverrideMethod of BaseClass";
        }
    }
    class ExtClass : BaseClass
    {
        public new string NewMethod()
        {
            return "NewMethod of ExtClass";
        }
        public override string VirtualOverrideMethod()
        {
            return "VirtualOverrideMethod of ExtClass";
        }
    }
    class LazyClass : BaseClass
    {
    }
}

输出:

NewMethod of BaseClass
VirtualOverrideMethod of BaseClass
---
NewMethod of ExtClass
VirtualOverrideMethod of ExtClass
---
NewMethod of BaseClass
VirtualOverrideMethod of ExtClass
---
VirtualOverrideMethod of BaseClass

2) 如果(1)不正确,我认为每个虚拟方法都必须在使用它的子类中重写,这是对的吗…

一点也不。virtual是一种表达方式,"如果你想覆盖这个方法,那没关系"。事实上,我在上面的代码中包含了LazyClass来展示这一点。

以上内容不会引起编译器的抱怨。。。

我不怎么使用接口,但看起来像一个。在我的代码中,如果我更改

    class ExtClass : BaseClass
    {
        public new string NewMethod()
        {
            return "NewMethod of ExtClass";
        }
        public override string VirtualOverrideMethod()
        {
            return "VirtualOverrideMethod of ExtClass";
        }
    }

至:

    class ExtClass : BaseClass
    {
        public new string NewMethod()
        {
            return "NewMethod of ExtClass";
        }
        public override string VirtualOverrideMethod()
        {
            return "VirtualOverrideMethod of ExtClass";
        }
    }

我得到:

error CS0501: 'OverrideTest.Program.ExtClass.VirtualOverrideMethod()' must declare a body because it is not marked abstract, extern, or partial

来自Visual Studio 2010。我的BaseClassvirtual方法也是如此。

virtual的需求是由多态性决定的。想想当您使用new:在子类中重新定义方法时会发生什么

class Parent
{
    void Foo() { Console.WriteLine("Parent"); }
    virtual void Bar { Console.WriteLine("Parent"); }
}
class Child : Parent
{
    new void Foo() { Console.WriteLine("Child"); } // another method Foo
    override void Bar { Console.WriteLine("Child"); }
}
var child = new Child();    // a Child instance
var parent = (Parent)child; // same object, but statically typed as Parent
c.Bar(); // prints "Child"
p.Bar(); // again, prints "Child" -- expected virtual behavior
c.Foo(); // prints "Child"
p.Foo(); // but this prints "Parent"!!

出于这个原因,打算从(即不是sealed)派生的类应该始终将可以重写的方法标记为virtual——否则会出现类似上述的令人困惑的运行时行为。父实现是否真的做了任何事情都没有区别;关键是它的行为不同

好吧,通过将方法声明为虚拟的(并且不希望覆盖子类中的方法),如果您要将同名方法引入子类,那么您将进入方法隐藏的世界。你必须这样定义它:

public abstract class A
{
    public virtual string GetName()
    {
        return null;
    }
}
public class B : A
{
    //assume there are some defined properties.
    public new string GetName()
    {
        return FirstName;
    }
}

我建议您考虑抽象覆盖方法:

public abstract class A
{
    public abstract string GetName()
}
// to override
public class B : A
{
    //assume there are some defined properties.
    public override string GetName()
    {
        return FirstName;
    }
}

这将大不相同。我强烈建议您只覆盖子类中的抽象方法。

然而,这里有一个关于这个主题的快速参考(旧的,但读起来很好):

http://www.akadia.com/services/dotnet_polymorphism.html

1) 如果一个方法没有实施当然,它可以在子类中被覆盖不使用虚拟和覆盖?

可以使用没有正文的abstract方法,但如果从该类派生,则必须覆盖该方法所有abstract方法都必须在子类中被覆盖

2) 如果(1)不正确,我认为每个虚拟方法必须在使用它的子类中重写…

不可以,相反,您可以使用virtual关键字在其内部实现,但请执行而不是使子类中的重写成为强制性的。从这个角度来看,给你更多的灵活性。

通常,他们使用abstract为子级创建刚性约束,因此从其派生的每个子级都必须实现基类的指定成员。

这正是virtualabstract方法之间的区别:

如果选择,虚拟方法可以被派生类覆盖。虚拟方法可能有也可能没有可供继承者调用的默认实现,这是使用base关键字完成的。

抽象方法必须被派生类覆盖。其限制条件是:

  • 它只能在抽象类中定义
  • 它不能有一个实现,因为它由继承者来定义它的行为