2013-05-08 74 views
10

考虑以下层次:通用包装类

class A 
{ 
} 
class B : A 
{ 
    public void Foo() { } 
} 
class C : A 
{ 
    public void Foo() { } 
} 

这是一个第三方库,我不能修改它。有没有办法我可以写一些'通用模板包装',将Foo()方法转发给作为构造函数参数传递的适当对象? 我最后写以下,其中不使用仿制药,似乎比较难看:

class Wrapper 
    { 
     A a; 
     public Wrapper(A a) 
     { 
      this.a = a; 
     } 

     public void Foo() 
     { 
      if (a is B) { (a as B).Foo(); } 
      if (a is C) { (a as C).Foo(); } 
     } 

    } 

我喜欢一些模板约束像Wrapper<T> where T : B or C

+1

我认为主要的问题是,'富''不是'虚拟'在'A',对吧? – dasblinkenlight 2013-05-08 10:59:14

回答

15

如果A没有Foo,你需要要么使用dynamic(见Jon Skeet's answer),或使用一个小技巧与lambda表达式和重载:

class Wrapper { 
    private Action foo; 
    public Wrapper(B b) { 
     foo =() => b.Foo(); 
    } 
    public Wrapper(C c) { 
     foo =() => c.Foo(); 
    } 
    public void Foo() { 
     foo(); 
    } 
} 

现在你可以这样做:

var wb = new Wrapper(new B()); 
wb.Foo(); // Call B's Foo() 
var wc = new Wrapper(new C()); 
wc.Foo(); // Call C's Foo() 

这对转移什么方法从目前的Foo打电话叫以创建Wrapper的那一刻,有可能挽救你一些CPU周期的决定。

+0

谢谢大家!我想我会为你的解决方案寻求更多类似Foo的功能,为简洁起见,我省略了这些功能。我还必须在我的代码中多次使用Wrapper,并且动态看起来过于内联解决方案。 – amnezjak 2013-05-08 11:23:18

7

不,这两个Foo方法就编译器而言是完全不相关的。这样做的不知道对各个类型先从最简单的方法是使用动态类型:

public void Foo() 
{ 
    dynamic d = a; 
    // Let's hope there's a suitable method at execution time! 
    d.Foo(); 
} 

仿制药不会帮助你在这里,至于我可以告诉。这不像是有一些界面(至少没有你显示过),你可以限制T

你可以传递一个Action还有:

Wrapper wrapper = new Wrapper(b, b.Foo); 

这使得它稍微少主叫方便,但很一般......

+1

这是Skeet大肚子。你摇动Skeet。 – JSJ 2013-05-08 11:06:28

+0

合并乔恩的“行动传递”与dasblinkenlight的建议和T4模板,你应该得到非常合理和可维护的解决方案。 – quetzalcoatl 2013-05-08 11:11:53

0

我不愿意表明它,但你不能修改库。如果这不是性能关键,召回dynamic关键字:)

class Wrapper 
{ 
    public dynamic theAorBorC; 

    public Wrapper(A a){theAorBorC=a;} 
    public Wrapper(B b){theAorBorC=b;} 
    public Wrapper(C c){theAorBorC=c;} 

    // or even... 
    // public Wrapper(object anything){theAorBorC=anything;} 

    public void CallFoo() 
    { 
     theAorBorC.Foo(); 
    } 
} 

编辑:在其他情况下,我个人使用类似于dasblinkenlight所显示的lambda - 来获得编译时检查。它可以很容易地自动生成,即使用T4或任何其他文本生成器。

0

您可以创建一个在根级别包含Foo()方法的并行分层结构。
使用工厂方法可以为任一类型创建包装实例。对于这个工作,你需要知道你的A实例的确切类型,当你调用工厂方法

abstract class Wrapper { 
    public abstract void Foo(); 

    //factory methods 
    public Wrapper FromB(B instance) { 
     return new WrapperB(instance); 
    } 
    public Wrapper FromC(C instance) { 
     return new WrapperB(instance); 
    } 
} 

class WrapperB { 
    private B instance {get; set;} 
    public WrapperB(B instance) { 
     this.instance = instance; 
    } 

    public void Foo() { 
     instance.Foo(); 
    } 
} 
class WrapperC { 
    private C instance {get; set;} 
    public WrapperC(C instance) { 
     this.instance = instance; 
    } 

    public void Foo() { 
     instance.Foo(); 
    } 
} 

编辑:这是基本相同this answer