2012-02-22 180 views
4

考慮以下代碼示例:有沒有辦法指定範圍?

public abstract class Parent 
{ 
    public int val; 
    public Parent() 
    { 
     val = 0; 
    } 
    public virtual void foo() 
    { 
     inc(); 
    } 

    public virtual void inc() 
    { 
     val = val + 10; 
    } 
} 

public class Child : Parent 
{ 
    public override void foo() 
    { 
     base.foo(); 
    } 

    public override void inc() 
    { 
     val++; 
    } 
} 

static void Main(string[] args) 
{ 
    Parent p = new Child(); 
    Console.WriteLine("p.val = " + p.val); //Output: p.val = 0 
    p.foo(); 
    Console.WriteLine("P.val = " + p.val); //Output: p.val = 1 
} 

我假設父類的inc()沒有得到調用,因爲{this}指針實際上指向一個子對象,這樣對孩子的的inc()版本將會從父對象的調用功能foo()。有沒有辦法強制父函數foo()總是調用父函數inc()就像你可以在C++中使用::運算符?

+1

如果Parent.inc()未聲明爲「虛擬」會怎麼樣? – niaher 2012-02-22 12:05:06

+1

這不是破壞了多態foo()的全部觀點嗎?即使你做了Parent :: foo(){this.inc()},它仍然會調用Child :: foo – StuartLC 2012-02-22 12:05:40

+1

我很肯定你可以用反射來完成它。當然,'base'關鍵字不支持C++的'::'支持的所有東西。 – CodesInChaos 2012-02-22 12:08:18

回答

6

你在想這個問題。

  • 如果你要非虛派遣然後不作方法擺在首位虛擬。

  • 如果你想虛擬和非虛擬調度然後使兩種方法,一種虛擬和一個靜態

例如:

class Base 
{ 
    protected static void NonVirtualFoo(Base b) 
    { 
     // Whatever 
    } 
    public virtual void Foo() 
    { 
     Base.NonVirtualFoo(this); 
    } 
} 

class Derived : Base 
{ 
    protected new static void NonVirtualFoo(Derived d) 
    { 
     // Whatever 
    } 
    public override void Foo() 
    { 
     Derived.NonVirtualFoo(this); 
     Base.NonVirtualFoo(this); 
    } 
} 

使用了正確的工具工作。如果你想虛擬調度,然後調用虛擬方法。如果你想靜態調度,那麼調用靜態方法。不要試圖採用虛擬方法來使其靜態派發;這與該工具的整個目的是一致的。

1

Child實例將調用它自己的類型實現。

foo()調用base.foo()base.foo()電話inc(),在這種情況下inc()是兒童,因爲實例是兒童型,並使用這個實現。

7

不,你可以調用一個虛擬的方法非幾乎是base.Foo的唯一途徑。當然,你可以在Parent非虛方法,使Parent.foo()呼叫,以及爲Parent.inc()默認實現。

0

那麼,它實際上是可能as said here

該做的伎倆:

public abstract class Parent 
{ 
    public int val; 

    public Parent() 
    { 
     val = 0; 
    } 

    public virtual void foo() 
    { 
     MethodInfo method = typeof(Parent).GetMethod("inc"); 
     DynamicMethod dm = new DynamicMethod("BaseInc", null, new Type[] { typeof(Parent) }, typeof(Parent)); 
     ILGenerator gen = dm.GetILGenerator(); 
     gen.Emit(OpCodes.Ldarg_1); 
     gen.Emit(OpCodes.Call, method); 
     gen.Emit(OpCodes.Ret); 

     var BaseInc = (Action<Parent>)dm.CreateDelegate(typeof(Action<Parent>)); 
     BaseInc(this); 
    } 

    public virtual void inc() 
    { 
     val = val + 10; 
    } 
} 

但它只是一個概念的證明:這是可怕完全打破了多態性

我不認爲你可以有一個正當的理由來寫這個。

+0

是否真的有必要使用codegen,而不是僅僅使用'method.Invoke(this,null)'方法進行普通反射? – svick 2012-02-22 16:24:32

+0

@svick是的。 'method.Invoke(this,null)'會調用override'inc'方法。 – ken2k 2012-02-22 16:32:40

相關問題