C# 是否可以覆盖非虚拟方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1853896/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to override a non-virtual method?
提问by zfedoran
Is there any way to override a non-virtual method? or something that gives similar results (other than creating a new method to call the desired method)?
有没有办法覆盖非虚拟方法?或者给出类似结果的东西(除了创建一个新方法来调用所需的方法)?
I would like to override a method from Microsoft.Xna.Framework.Graphics.GraphicsDevice
with unit testing in mind.
我想从Microsoft.Xna.Framework.Graphics.GraphicsDevice
单元测试中覆盖一个方法。
采纳答案by Andrew Hare
No, you cannot override a non-virtual method. The closest thing you can do is hide the method by creating a new
method with the same name but this is not advisable as it breaks good design principles.
不,您不能覆盖非虚拟方法。您可以做的最接近的事情是通过创建一个new
具有相同名称的方法来隐藏该方法,但这不是可取的,因为它违反了良好的设计原则。
But even hiding a method won't give you execution time polymorphic dispatch of method calls like a true virtual method call would. Consider this example:
但是即使隐藏一个方法也不会给你像真正的虚方法调用那样的方法调用多态分派的执行时间。考虑这个例子:
using System;
class Example
{
static void Main()
{
Foo f = new Foo();
f.M();
Foo b = new Bar();
b.M();
}
}
class Foo
{
public void M()
{
Console.WriteLine("Foo.M");
}
}
class Bar : Foo
{
public new void M()
{
Console.WriteLine("Bar.M");
}
}
In this example both calls to the M
method print Foo.M
. As you can see this approach does allow you to have a new implementation for a method as long as the reference to that object is of the correct derived type but hiding a base method doesbreak polymorphism.
在这个例子中,都调用了M
方法 print Foo.M
。正如您所看到的,只要对该对象的引用是正确的派生类型,这种方法确实允许您为该方法提供新的实现,但隐藏基方法确实会破坏多态性。
I would recommend that you do not hide base methods in this manner.
我建议您不要以这种方式隐藏基本方法。
I tend to side with those who favor C#'s default behavior that methods are non-virtual by default (as opposed to Java). I would go even further and say that classes should also be sealed by default. Inheritance is hard to design for properly and the fact that there is a method that is not marked to be virtual indicates that the author of that method never intended for the method to be overridden.
我倾向于支持 C# 的默认行为,即默认方法是非虚拟的(与 Java 相对)。我会更进一步说,默认情况下也应该密封类。继承很难正确设计,并且存在未标记为虚拟的方法这一事实表明该方法的作者从未打算覆盖该方法。
Edit: "execution time polymorphic dispatch":
编辑:“执行时间多态调度”:
What I mean by this is the default behavior that happens at execution time when you call virtual methods. Let's say for example that in my previous code example, rather than defining a non-virtual method, I did in fact define a virtual method and a true overridden method as well.
我的意思是当您调用虚拟方法时,在执行时发生的默认行为。例如,在我之前的代码示例中,我没有定义非虚拟方法,而是实际上定义了一个虚拟方法和一个真正的重写方法。
If I were to call b.Foo
in that case, the CLR would correctly determine the type of object that the b
reference points to as Bar
and would dispatch the call to M
appropriately.
如果我b.Foo
在这种情况下调用,CLR 将正确确定b
引用指向的对象类型,Bar
并将调用M
适当地分派到。
回答by ChrisF
回答by slugster
If the base class isn't sealed then you can inherit from it and write a new method that hides the base one (use the "new" keyword in the method declaration). Otherwise no, you cannot override it because it was never the original authors intent for it to be overridden, hence why it isn't virtual.
如果基类不是密封的,那么您可以从它继承并编写一个隐藏基类的新方法(在方法声明中使用“new”关键字)。否则,您无法覆盖它,因为原始作者从未打算将其覆盖,因此它不是虚拟的。
回答by Rory
I think you're getting overloading and overriding confused, overloading means you have two or more methods with the same name but different sets of parameters while overriding means you have a different implementation for a method in a derived class (thereby replacing or modifying the behaviour in it's base class).
我认为您对重载和覆盖感到困惑,重载意味着您有两个或更多名称相同但参数集不同的方法,而覆盖意味着您对派生类中的方法有不同的实现(从而替换或修改行为在它的基类中)。
If a method is virtual, you can override it using the override keyword in the derrived class. However, non-virtual methods can only hide the base implementation by using the new keyword in place of the override keyword. The non-virtual route is useless if the caller accesses the method via a variable typed as the base type as the compiler would use a static dispatch to the base method (meaning the code in your derrived class would never be called).
如果方法是虚拟的,您可以使用派生类中的 override 关键字覆盖它。但是,非虚拟方法只能通过使用 new 关键字代替 override 关键字来隐藏基本实现。如果调用者通过类型为基类型的变量访问方法,则非虚拟路由是无用的,因为编译器将使用静态分派到基方法(意味着永远不会调用派生类中的代码)。
There is never anything preventing you from adding an overload to an existing class, but only code that knows about your class would be able to access it.
永远不会阻止您向现有类添加重载,但只有了解您的类的代码才能访问它。
回答by ShivanandSK
There is a way of achieving this using abstract class and abstract method.
有一种方法可以使用抽象类和抽象方法来实现这一点。
Consider
考虑
Class Base
{
void MethodToBeTested()
{
...
}
void Method1()
{
}
void Method2()
{
}
...
}
Now, if you wish to have different versions of method MethodToBeTested(), then change Class Base to an abstract class and method MethodToBeTested() as an abstract method
现在,如果您希望有不同版本的 MethodToBeTested() 方法,则将 Class Base 更改为抽象类,并将 MethodToBeTested() 方法更改为抽象方法
abstract Class Base
{
abstract void MethodToBeTested();
void Method1()
{
}
void Method2()
{
}
...
}
With abstract void MethodToBeTested() comes an issue; the implementation is gone.
抽象 void MethodToBeTested() 带来了一个问题;实施消失了。
Hence create a class DefaultBaseImplementation : Base
to have the default implementation.
因此创建一个class DefaultBaseImplementation : Base
具有默认实现。
And create another class UnitTestImplementation : Base
to have unit test implementation.
并创建另一个class UnitTestImplementation : Base
以进行单元测试实现。
With these 2 new classes, the base class functionality can be overridden.
使用这 2 个新类,可以覆盖基类功能。
Class DefaultBaseImplementation : Base
{
override void MethodToBeTested()
{
//Base (default) implementation goes here
}
}
Class UnitTestImplementation : Base
{
override void MethodToBeTested()
{
//Unit test implementation goes here
}
}
Now you have 2 classes implementing (overriding) MethodToBeTested()
.
现在您有 2 个类实现 (overriding) MethodToBeTested()
。
You can instantiate the (derived) class as required (i.e. either with base implementation or with unit test implementation).
您可以根据需要(即使用基本实现或单元测试实现)实例化(派生)类。
回答by user3853059
In the case you are inheriting from a non-derived class, you could simply create an abstract super class and inherit from it downstream instead.
如果您从非派生类继承,您可以简单地创建一个抽象超类并从它下游继承。
回答by Aaron Thomas
Is there any way to override a non-virtual method? or something that gives similar results (other than creating a new method to call the desired method)?
有没有办法覆盖非虚拟方法?或者给出类似结果的东西(除了创建一个新方法来调用所需的方法)?
You cannot override a non-virtual method. However you canuse the new
modifier keyword to get similar results:
您不能覆盖非虚拟方法。但是,您可以使用new
修饰符关键字来获得类似的结果:
class Class0
{
public int Test()
{
return 0;
}
}
class Class1 : Class0
{
public new int Test()
{
return 1;
}
}
. . .
// result of 1
Console.WriteLine(new Class1().Test());
You will also want to make sure that the access modifieris also the same, otherwise you will not get inheritance down the line. If another class inherits from Class1
the new
keyword in Class1
will not affect objects inheriting from it, unless the access modifier is the same.
您还需要确保访问修饰符也相同,否则您将无法获得继承。如果从另一个类继承Class1
的new
关键字Class1
不会影响对象从它继承,除非访问修饰符是一样的。
If the access modifier is notthe same:
如果访问修饰符是不一样的:
class Class0
{
protected int Test()
{
return 0;
}
}
class Class1 : Class0
{
// different access modifier
new int Test()
{
return 1;
}
}
class Class2 : Class1
{
public int Result()
{
return Test();
}
}
. . .
// result of 0
Console.WriteLine(new Class2().Result());
...versus if the access modifier isthe same:
...如果与访问修饰符是一样的:
class Class0
{
protected int Test()
{
return 0;
}
}
class Class1 : Class0
{
// same access modifier
protected new int Test()
{
return 1;
}
}
class Class2 : Class1
{
public int Result()
{
return Test();
}
}
. . .
// result of 1
Console.WriteLine(new Class2().Result());
As pointed out in a previous answer, this is not a good design principle.
正如之前的回答中所指出的,这不是一个好的设计原则。
回答by Vyacheslav Napadovsky
You can't override non-virtual method of any class in C# (without hacking CLR), but you can override any method of interface the class implements. Consider we have non-sealed
您不能在 C# 中覆盖任何类的非虚拟方法(无需破解 CLR),但您可以覆盖该类实现的任何接口方法。考虑我们有非密封
class GraphicsDevice: IGraphicsDevice {
public void DoWork() {
Console.WriteLine("GraphicsDevice.DoWork()");
}
}
// with its interface
interface IGraphicsDevice {
void DoWork();
}
// You can't just override DoWork in a child class,
// but if you replace usage of GraphicsDevice to IGraphicsDevice,
// then you can override this method (and, actually, the whole interface).
class MyDevice: GraphicsDevice, IGraphicsDevice {
public new void DoWork() {
Console.WriteLine("MyDevice.DoWork()");
base.DoWork();
}
}
And here's demo
这是演示
class Program {
static void Main(string[] args) {
IGraphicsDevice real = new GraphicsDevice();
var myObj = new MyDevice();
// demo that interface override works
GraphicsDevice myCastedToBase = myObj;
IGraphicsDevice my = myCastedToBase;
// obvious
Console.WriteLine("Using real GraphicsDevice:");
real.DoWork();
// override
Console.WriteLine("Using overriden GraphicsDevice:");
my.DoWork();
}
}