2011-09-05 110 views
2

在下面的代码我定义一个接口,一个抽象基类与打印“foo”的方法,同时实现的一类,以及与等于的方法的签名的接口上的扩展方法在打印“bar”的抽象基类中。当我运行这个样本,为什么是“巴”字样,而不是“富”?如果适用,这种语言设计选择背后的士气是什么?扩展方法中重写继承的方法

public interface ISomething 
{} 

public abstract class SomethingElse 
{ 
    public void foo() 
    { 
     Console.WriteLine("foo"); 
    } 
} 

public class DefinitelySomething : SomethingElse, ISomething 
{} 

public static class ISomethingExtensions 
{ 
    public static void foo(this ISomething graphic) 
    { 
     Console.WriteLine("bar"); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     ISomething g = new DefinitelySomething(); 
     g.foo(); 
    } 
} 

回答

5

由于变量声明为ISomething

实例方法是未知的,直到运行时间,不过方法重载方案是在编译时。不能保证实例实际上有一个合适的方法。在你具体的例子有,但是从类型安全的角度这是一个不相关的巧合。在该行g.foo()重要的类型是G是声明不运行时类型

+0

我接受这个答案,因为对我来说这是解释继承和扩展方法在这个问题背后的最理解的答案。 – mtijn

9

ISomething不具有构件称为foo,所以扩展方法将被调用。

0

在这种情况下,你叫ISomethingfoo方法的类型,它被分解为扩展方法。

如果您使用此代码:

ISomething g = new DefinitelySomething(); 
(g as SomethingElse).foo(); 

你会得到正确的输出。

1

SomethingElse上的foo方法不考虑用于重载分辨率,因为您正在对ISomething实例进行操作。

还是要想想另一种方式,可以考虑,如果你没有任何扩展方法会发生什么?在这种情况下,您将收到编译错误,因为找不到其他合适的方法。

试着改变你的代码如下:

DefinitelySomething g = new DefinitelySomething(); 
g.foo(); 

它应该表现你是如何期待。

0

你总是可以扩展方法内部检查,看看是否你目前正在使用的对象具有完全相同的签名

public static System.Reflection.MethodInfo ExtensionOverrider(this Object obj, System.Reflection.MethodInfo method) 
    { 
     return obj.GetType().GetMethods().Where(
      x => x.Name == method.Name && 
      x.GetParameters().Select(z => z.ParameterType).SequenceEqual(method.GetParameters().Skip(1).Select(w => w.ParameterType))).FirstOrDefault(); 
    } 


    public static void foo(this ISomething graphic) 
    { 
     var Method = graphic.ExtensionOverrider(System.Reflection.MethodBase.GetCurrentMethod());     
     if(Method != null) 
      Method.Invoke(graphic, new Object[0]{}); 
     else 
      Console.WriteLine("bar"); 
    } 
-1

只是一些例子,在LinqPad测试现有的方法。 注意,该项目宣布为ISomething使用扩展方法,并返回“酒吧”,其作为@leppie pointed out是因为ISomething没有一个方法foo,但在新的实例调用foo直接给出正确的输出“富“

void Main(string[] args) { 
     // baseline 
     var g0 = new DefinitelyNothing();     g0.foo(); // "foo" 

     ISomething g; 

     // won't work, not ISomething 
     // g = new DefinitelyNothing();  g.foo(); 

     g = new DefinitelyNothingThatThinksItsSomething(); g.foo(); // "bar" 
      new DefinitelyNothingThatThinksItsSomething().foo(); // "foo" 

     g = new DefinitelySomething();      g.foo(); // "bar" 
      new DefinitelySomething().foo();      // "foo" 

     g = new DefinitelySomethingWithFoo();    g.foo(); // "bar" 
      new DefinitelySomethingWithFoo().foo();     // "foo" 
      (g as IWithFoo).foo();         // "foo", not "qux" 

     g = new DefinitelySomethingFromNothingWithFoo(); g.foo(); // "bar" 
      new DefinitelySomethingFromNothingWithFoo().foo();  // "foo" 
      (g as ISomethingWithFoo).foo();       // "foo", not "baz" 

     IWithFoo g1; 
     g1 = new DefinitelyNothingWithFoo();    g1.foo(); // "foo" 
      new DefinitelyNothingWithFoo().foo();     // "foo" 
} 

public interface ISomething {} 
public interface IWithFoo { 
    void foo(); 
} 
public interface ISomethingWithFoo : ISomething, IWithFoo {} 

public abstract class Nothing { 
    public void foo() { Console.WriteLine("foo"); } 
} 
public abstract class NothingWithFoo : IWithFoo { 
    public void foo() { Console.WriteLine("foo"); } 
} 
public abstract class Something : ISomething { 
    public void foo() { Console.WriteLine("foo"); } 
} 
public abstract class SomethingWithFoo : ISomethingWithFoo { 
    public void foo() { Console.WriteLine("foo"); } 
} 
public abstract class SomethingFromNothingWithFoo : Nothing, ISomethingWithFoo {} 

public class DefinitelyNothing: Nothing {} 
public class DefinitelyNothingThatThinksItsSomething: Nothing, ISomething {} 
public class DefinitelyNothingWithFoo : NothingWithFoo {} 

public class DefinitelySomething : Something {} 
public class DefinitelySomethingWithFoo : SomethingWithFoo {} 
public class DefinitelySomethingFromNothingWithFoo : SomethingFromNothingWithFoo {} 


public static class ISomethingExtensions { 
    // http://en.wikipedia.org/wiki/Metasyntactic_variable 
    public static void foo(this ISomething whatever) { Console.WriteLine("bar"); } 
    public static void foo(this ISomethingWithFoo whatever) { Console.WriteLine("baz"); } 
    public static void foo(this IWithFoo whatever) { Console.WriteLine("qux"); } 
}