2010-07-08 71 views
3

我有一组我没有写的类,它们是只读的。 比方说,对于例如,这些类是以下物质:C#:具有非多态类的动态多态性

public class Base { } 
public class B : Base { } 
public class C : B { } 
public class D : Base { } 

我想对所有这些类添加一个方法Foo(),我使用的扩展方法:

public static class Extensions { 

    public static void Foo(this Base obj) { 
     dynamic dynobj = obj; 
     try { 
     dynobj.Foo(); 
     } 
     catch (RuntimeBinderException ex) { 
      Console.WriteLine(ex.Message); 
     } 
    } 

    public static void Foo(this B b) { 
     Console.WriteLine("Foo in B"); 
    } 

    public static void Foo(this C c) { 
     Console.WriteLine("Foo in C"); 
    } 

} 

正如你可以看到,我试图使用关键字dynamic,期望它知道我的对象的实际类型并调用它的Foo()方法。但是... dynobj.Foo()总是失败。

static void Main(string[] args) { 
    List<Base> list = new List<Base>(); 
    list.Add(new B()); 
    list.Add(new C()); 
    list.Add(new D()); 

    list.ForEach(x => x.Foo()); 
} 

我知道我可以使用适配器模式,但我真的有太多的类。

dynamic这样做是个好主意吗?是否有可能做到这一点?

谢谢。

回答

1

我只保留基地” Foo()扩展方法,使其他分机方法常规静态方法服用BCD作为参数排序的解决我的问题。

public static void Foo(this Base obj) { 
     try { 
     Foo_(obj as dynamic); 
     } 
     catch (RuntimeBinderException ex) { 
      Console.WriteLine(ex.Message); 
     } 
    } 

    private static void Foo_(B b) { 
     Console.WriteLine("Foo in B"); 
     b.ListOfBs.ForEach(x => x.Foo()); 
    } 

    private static void Foo_(C c) { 
     Console.WriteLine("C.Name = {0}", c.Name); 
    } 
5

这是因为Foo永远不会被添加为方法。扩展方法仍然只是静态类中的静态方法,实际上并不直接与相关类相关联。他们不喜欢混插(ruby)。编译器只是将对象上的调用转换为静态方法。

与调用:Extensions.Foo(thing)

我最好的建议是创建一个查找表(词典),您可以注册不同版本的Foo。

像这样(未经测试),也许?

public static class Extensions { 

    private static Dictionary<Type, Action<Base>> callFoo = new Dictionary<Type, Action<Base>> 
    { 
    {typeof(B), b => (b as B).Foo()}, 
    {typeof(C), b => (b as C).Foo()} 
    }; 

    public static void Foo(this Base obj) { 
     try { 
     callFoo[typeof(obj)](obj); 
     } 
     catch (RuntimeBinderException ex) { 
      Console.WriteLine(ex.Message); 
     } 
    } 

    public static void Foo(this B b) { 
     Console.WriteLine("Foo in B"); 
    } 

    public static void Foo(this C c) { 
     Console.WriteLine("Foo in C"); 
    } 

} 
+0

哦..好的,谢谢。这很整洁,但我想要一些更有活力的东西。 – 2010-07-08 12:27:15

+0

我不认为你会找到扩展方法的动态解决方案。 :(我可以被比我更有创意的人证明是错误的,尽管:) – 2010-07-08 12:45:55

+0

是的,你说得对。但是我意识到Base的Foo()是足够的,因为它可以用于从Base继承的其他类型。 – 2010-07-08 13:07:01

0

还有另一个原因,您的解决方案不会是一个好主意 - Base没有被定义为一个抽象类,所以有一个机会,有人能初始化它,而且即使你的技术工作,碰上如果他们试图调用Foo()方法,则会导致堆栈溢出。 ()调用C类的Foo()扩展方法的实例最终达到B的Foo()扩展方法)吗?如果你带走Base的Foo()方法,Foo

如果它不起作用,您可以永远老式并创建包装类。

+0

嗯,我不好,你说得对,'Base'是一个抽象类,当我简化我的例子的时候,我把它排除了。其实我真的需要'Base'的'Foo()'方法,因为它是派遣的人。 – 2010-07-08 12:32:14