2011-05-12 172 views
23

我有一個情況,其中兩班(從另一個推導)都實現明確的相同的接口:如何調用基類的顯式實現接口方法

interface I 
{ 
    int M(); 
} 
class A : I 
{ 
    int I.M() { return 1; } 
} 
class B : A, I 
{ 
    int I.M() { return 2; } 
} 

從派生類執行I.M(),我想調用基類的實現,但我不知道該怎麼做。我試過到目前爲止,這是(B類):

int I.M() { return (base as I).M() + 2; } 
// this gives a compile-time error 
//error CS0175: Use of keyword 'base' is not valid in this context 

int I.M() { return ((this as A) as I).M() + 2; } 
// this results in an endless loop, since it calls B's implementation 

有沒有辦法做到這一點,而無需執行其他(非界面顯式)輔助方法?


更新

我知道這是可能的一個「助手」方法,可以通過派生類中調用,如:

class A : I 
{ 
    int I.M() { return M2(); } 
    protected int M2 { return 1; } 
} 

我也可以改變它來實現界面非明確。但我只是想知道是否有可能沒有任何這些解決方法。

回答

17

不幸的是,這是不可能的。
甚至沒有輔助方法。輔助方法有同樣的問題,你的第二次嘗試:thisB型的,即使是在基類,並調用M的實施B

interface I 
{ 
    int M(); 
} 
class A : I 
{ 
    int I.M() { return 1; } 
    protected int CallM() { return (this as I).M(); } 
} 
class B : A, I 
{ 
    int I.M() { return CallM(); } 
} 

唯一的解決辦法是在A一個輔助方法即在A的實施M使用:

interface I 
{ 
    int M(); 
} 
class A : I 
{ 
    int I.M() { return CallM(); } 
    protected int CallM() { return 1; } 
} 
class B : A, I 
{ 
    int I.M() { return CallM(); } 
} 

但是,你將需要提供一種方法,這樣也爲B是否會有一個class C : B, I ...

+0

是的,解決方法是我已經添加到更新的問題。但這不是我想知道的。 – M4N 2011-05-12 10:06:01

+1

@ M4N:這只是爲了讓答案更大一些;-)真正的答案是第一句話:沒有這種解決方法,這是不可能的。 – 2011-05-12 10:07:50

+4

要添加到爲什麼它是不可能的:明確實現的接口方法是私有的 - 使他們無法從派生類調用。您應該更喜歡不同的方法,比如Daniel列出的方法,以避免*調用super *代碼味道。 – 2011-05-12 10:18:57

0

它需要明確嗎?...您可以使用抽象類或類而不是接口嗎?

interface ISample {} 
class A : ISample {} 
class B : A {} 
... 
base.fun(); 
... 

http://msdn.microsoft.com/en-us/library/hfw7t1ce(v=vs.71).aspx

我不知道它不可能調用基方法時,它來自實現的接口。

+0

不! B具有不同於A的接口實現(它增加了A的實現)。 – M4N 2011-05-12 09:56:10

+0

@ M4N - 然後你只能擴展A覆蓋該方法並對該方法進行基礎調用並繼續實現該方法。 – Amedio 2011-05-12 10:00:30

+0

查看更新的問題。 (顯式實現不是必需的,但我只是想知道是否有可能) – M4N 2011-05-12 10:03:48

10

可以使用反射。
代碼如下。我將緩存添加爲基本優化,但可以使用Delegate.CreateDelegatemethodInfo進行進一步優化。此外,可以使用methodInfo.GetParameters()添加參數計數和類型檢查。

interface I 
{ 
    int M(); 
} 

class A : I 
{ 
    int I.M() { return 1; } 
} 

class B : A, I 
{ 
    BaseClassExplicitInterfaceInvoker<B> invoker = new BaseClassExplicitInterfaceInvoker<B>(); 
    int I.M() { return invoker.Invoke<int>(this, "M") + 2; } 
} 

public class BaseClassExplicitInterfaceInvoker<T> 
{ 
    private Dictionary<string, MethodInfo> cache = new Dictionary<string, MethodInfo>(); 
    private Type baseType = typeof(T).BaseType; 

    private MethodInfo FindMethod(string methodName) 
    { 
     MethodInfo method = null; 
     if (!cache.TryGetValue(methodName, out method)) 
     { 
      var methods = baseType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); 

      foreach (var methodInfo in methods) 
      { 
       if (methodInfo.IsFinal && methodInfo.IsPrivate) //explicit interface implementation 
       { 
        if (methodInfo.Name == methodName || methodInfo.Name.EndsWith("." + methodName)) 
        { 
         method = methodInfo; 
         break; 
        } 
       } 
      } 

      cache.Add(methodName, method); 
     } 

     return method; 
    } 

    public RT Invoke<RT>(T obj, string methodName) 
    {    
     MethodInfo method = FindMethod(methodName); 
     return (RT)method.Invoke(obj, null); 
    } 

} //public static class BaseClassExplicitInterfaceInvoker<T> 

Here是我的靈感來源。

+0

工程就像一個魅力。在這種情況下,反思就是要走的路。 – 2013-02-01 12:02:48

+2

僅僅因爲你可以做某件事情並不意味着你必須這樣做。 – Unknown 2013-03-25 12:34:53

+1

僅僅因爲你應該考慮不做某事並不意味着沒有這樣做的實例是不可或缺的;-) @Roland,感謝分享,是一種享受! – Dav 2014-05-21 22:58:06

0

你不能調用顯式接口方法的基類,在這裏,我解決了這個問題

我有兩個界面 - >接口1和接口2

public interface Interface1 
{  
    string method2();  
} 

public interface Interface2 
{ 
    string method22(); 

} 

主要類的方法

class Program 
{ 
    static void Main(string[] args) 
    { 

     class1 cls = new class1(); 
     string str = cls.method2(); 
    } 
} 

和我的接口實現類

class class1 : Interface1, Interface2 
{ 

    #region Interface1 Members 

    public string method2() 
    { 
     return (this as Interface2).method22(); 
    }  

    #endregion 

    #region Interface2 Members  

    string Interface2.method22() 
    { 
     return "2"; 
    } 

    #endregion 
} 
0
using System; 

namespace SampleTest 
{ 
    interface IInterface1 
    { 
     void Run(); 
    } 

    interface IInterface2 
    { 
     void Run(); 
    } 

    public class BaseClass : IInterface1, IInterface2 
    { 
     public void Interface1Run() 
     { 
      (this as IInterface1).Run(); 
     } 

     public void Interface2Run() 
     { 
      (this as IInterface2).Run(); 
     } 

     void IInterface2.Run() 
     { 
      Console.WriteLine("I am from interface 2"); 
     } 

     void IInterface1.Run() 
     { 
      Console.WriteLine("I am from interface 1"); 
     } 
    } 

    public class ChildClass : BaseClass 
    { 
     public void ChildClassMethod() 
     { 
      Interface1Run(); 
      Interface2Run();  
     } 
    } 
    public class Program : ChildClass 
    { 
     static void Main(string[] args) 
     { 
      ChildClass childclass = new ChildClass(); 
      childclass.ChildClassMethod(); 
     } 
    } 
} 
+1

添加一些探索 – HaveNoDisplayName 2016-09-04 04:07:37

0

這是我的Roland Pihlakas的解決方案。該版本支持整個繼承鏈而不是直接的基類。 Invoke方法包含其他參數,並且有一個用於非函數方法的void類型Invoke。

public class BaseClassExplicitInterfaceInvoker<T> 
{ 
    readonly Dictionary<string, MethodInfo> Cache = new Dictionary<string, MethodInfo>(); 

    MethodInfo FindMethod(string MethodName) 
    { 
     if (Cache.TryGetValue(MethodName, out var Result)) return Result; 

     var BaseType = typeof(T); 
     while (Result == null) 
     { 
      if ((BaseType = BaseType.BaseType) == typeof(object)) break; 

      var Methods = BaseType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); 
      Result = Methods.FirstOrDefault(X => X.IsFinal && X.IsPrivate && (X.Name == MethodName || X.Name.EndsWith("." + MethodName))); 
     } 

     if (Result != null) Cache.Add(MethodName, Result); 

     return Result; 
    } 

    public void Invoke(T Object, string MethodName, params object[] Parameters) => FindMethod(MethodName).Invoke(Object, Parameters); 
    public ReturnType Invoke<ReturnType>(T Object, string MethodName, params object[] Parameters) => (ReturnType)FindMethod(MethodName).Invoke(Object, Parameters); 
} 
相關問題