通用包装类

时间:2013-05-08 10:57:10

标签: c# c#-4.0

给出以下层次结构:

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这样的模板约束。

4 个答案:

答案 0 :(得分: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周期。

答案 1 :(得分:8)

不,就编译器而言,两个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);

这使得调用者稍微不方便,但非常一般......

答案 2 :(得分: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();
    }
}

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

答案 3 :(得分:0)

您可以创建一个在根级别包含Foo()方法的并行层次结构 使用工厂方法,您可以为任一类型创建Wrapper实例。为此,您需要在调用工厂方法时了解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

基本相同