Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 泛型包装类_C#_C# 4.0 - Fatal编程技术网

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();
    }
}