C# 泛型包装类
考虑到以下层次结构:C# 泛型包装类,c#,c#-4.0,C#,C# 4.0,考虑到以下层次结构: class A { } class B : A { public void Foo() { } } class C : A { public void Foo() { } } 这是第三方库,我无法修改它。有没有办法编写某种“通用模板包装器”,将Foo()方法转发给作为构造函数参数传递的适当对象? 我最后写了以下内容,没有使用泛型,看起来相当难看: class Wrapper { A a; public Wrappe
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(); }
}
}
我喜欢一些模板约束,比如
包装,其中T:B或C
不,就编译器而言,这两个Foo
方法是完全不相关的。在不知道要开始使用的单个类型的情况下,最简单的方法是使用动态类型:
public void Foo()
{
dynamic d = a;
// Let's hope there's a suitable method at execution time!
d.Foo();
}
据我所知,仿制药在这方面帮不了你。它不像是有一些可以约束T
的接口(至少没有显示)
您还可以传入操作
:
Wrapper wrapper = new Wrapper(b, b.Foo);
这使得调用者稍微不方便,但非常普遍…如果
A
没有Foo
,则需要使用动态
(请参阅)或使用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周期。我不愿意建议这样做,但因为您无法修改库。。如果这不是性能关键问题,请调用动态
关键字:)
编辑:在所有其他情况下,我个人使用lambdas类似于dasblinkenlight所显示的,以获得编译时检查。它可以很容易地自动生成,即使用T4s或任何其他文本生成器。您可以创建一个并行层次结构,其中包含根级别的
Foo()
方法。使用工厂方法,您可以为任一类型创建包装器实例。为了实现这一点,在调用factory方法时,您需要知道
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();
}
}
编辑:这基本上与相同,我假设主要问题是
Foo
在A
中不是virtual
,对吧?这是飞碟肚。把Jon的“动作传递”与dasblinkenlight的建议和T4模板结合起来,你应该得到非常合理和可维护的解决方案。谢谢大家!我想我支持您的解决方案,因为有更多类似于Foo的函数,为了简洁起见,我省略了这些函数。我还必须在代码中多次使用包装器,而dynamic似乎是一个过于内联的解决方案。
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();
}
}