C# - 在类中使用多态,我没写

时间:2009-03-25 20:54:25

标签: c# architecture inheritance polymorphism

在无法修改的类中实现多态行为的最佳方法是什么?我目前有一些代码:

if(obj is ClassA) {
    // ...
} else if(obj is ClassB) {
    // ...
} else if ...

显而易见的答案是向基类添加一个虚方法,但不幸的是代码在不同的程序集中,我无法修改它。有没有比上面的丑陋和慢速代码更好的方法来处理这个问题?

5 个答案:

答案 0 :(得分:9)

嗯...似乎更适合Adapter

public interface ITheInterfaceYouNeed
{
    void DoWhatYouWant();
}

public class MyA : ITheInterfaceYouNeed
{
    protected ClassA _actualA;

    public MyA( ClassA actualA )
    {
        _actualA = actualA;
    }

    public void DoWhatYouWant()
    {
        _actualA.DoWhatADoes();
    }
}

public class MyB : ITheInterfaceYouNeed
{
    protected ClassB _actualB;

    public MyB( ClassB actualB )
    {
        _actualB = actualB;
    }

    public void DoWhatYouWant()
    {
        _actualB.DoWhatBDoes();
    }
}

看起来像很多代码,但它会使客户端代码更接近你想要的。此外,它还会让您有机会思考您实际使用的界面。

答案 1 :(得分:5)

查看Visitor模式。这使您可以在不更改类的情况下将虚拟方法添加到类中。如果您正在使用的基类没有Visit方法,则需要使用带有动态强制转换的扩展方法。这是一些示例代码:

public class Main
{
    public static void Example()
    {
        Base a = new GirlChild();
        var v = new Visitor();
        a.Visit(v);
    }
}

static class Ext
{
    public static void Visit(this object b, Visitor v)
    {
        ((dynamic)v).Visit((dynamic)b);
    }
}

public class Visitor
{
    public void Visit(Base b)
    {
        throw new NotImplementedException();
    }

    public void Visit(BoyChild b)
    {
        Console.WriteLine("It's a boy!");
    }

    public void Visit(GirlChild g)
    {
        Console.WriteLine("It's a girl!");            
    }
}
//Below this line are the classes you don't have to change.
public class Base
{
}

public class BoyChild : Base
{
}

public class GirlChild : Base
{
}

答案 2 :(得分:0)

我想说这里的标准方法是将你想要“继承”的类包装为受保护的实例变量,然后模拟包装类的所有非私有成员(方法/属性/事件/等)。在你的容器类中。然后,您可以将此类及其适当的成员标记为虚拟,以便您可以使用标准多态性功能。

这是我的意思的一个例子。 ClosedClass是程序集中包含的类,您的代码无权访问。

public virtual class WrapperClass : IClosedClassInterface1, IClosedClassInterface2
{
    protected ClosedClass object;

    public ClosedClass()
    {
        object = new ClosedClass();
    }

    public void Method1()
    {
        object.Method1();
    }

    public void Method2()
    {
        object.Method2();
    }
}

如果您引用的任何程序集都设计得很好,那么您可能想要访问的所有类型/成员都将被适当地标记(抽象,虚拟,密封),但实际上并非如此(有时您可以甚至在基类库中遇到过这个问题。在我看来,包装类是走到这里的方式。它确实有它的好处(即使你想要派生的类可继承的),即删除/更改你不希望你的类的用户有权访问的方法的修饰符。 BCL中的ReadOnlyCollection<T>就是一个非常好的例子。

答案 3 :(得分:0)

看一下Decorator模式。 Noldorin实际上解释了它而没有给出模式的名称。

Decorator是在不继承的情况下扩展行为的方式。我在Noldorin代码中唯一要改变的是构造函数应该接收你正在装饰的对象的实例。

答案 4 :(得分:-1)

Extension methods提供了一种向现有类添加其他方法签名的简便方法。这需要3.5框架。

创建一个静态实用程序类并添加如下内容:

public static void DoSomething(this ClassA obj, int param1, string param2)
{
    //do something
}

在页面上添加对实用程序类的引用,此方法将显示为ClassA的成员。您可以通过这种方式重载现有方法或创建新方法。