通用包装类

amn*_*jak 10 c# c#-4.0

给定以下层次结构:

class A
{
}
class B : A
{
    public void Foo() { }
}
class C : A
{
    public void Foo() { } 
}
Run Code Online (Sandbox Code Playgroud)

这是第三方库,我无法修改它.有没有办法可以编写某种"通用模板化包装器",将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(); }
        }

    }
Run Code Online (Sandbox Code Playgroud)

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

das*_*ght 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以这样做:

var wb = new Wrapper(new B());
wb.Foo(); // Call B's Foo()
var wc = new Wrapper(new C());
wc.Foo(); // Call C's Foo()
Run Code Online (Sandbox Code Playgroud)

这将决定从Foo调用的那一刻到Wrapper创建的那一刻调用什么方法,这可能会节省一些CPU周期.


Jon*_*eet 8

不,Foo就编译器而言,这两种方法完全不相关.在知道开始使用的各个类型的情况下,最简单的方法是使用动态类型:

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

据我所知,泛型不会帮助你.它不像是你可以约束的某个界面(至少没有你展示过的界面)T.

你也可以传入一个Action:

Wrapper wrapper = new Wrapper(b, b.Foo);
Run Code Online (Sandbox Code Playgroud)

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