给出以下层次结构:
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
这样的模板约束。
答案 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
基本相同