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.

4

4 回答 4

15

如果A没有Foo,您需要使用dynamic(参见Jon Skeet 的回答)或使用 lambdas 和重载的小技巧:

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 周期。

于 2013-05-08T11:06:06.660 回答
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);

这对调用者来说稍微不方便,但很笼统......

于 2013-05-08T11:00:35.287 回答
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 所展示的 lambdas 来进行编译时检查。它可以很容易地自动生成,即使用 T4s 或任何其他文本生成器。

于 2013-05-08T11:07:58.073 回答
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();
    }
}

编辑:这与这个答案基本相同

于 2013-05-08T11:08:24.707 回答