一种将基类型转换为派生类型的方法

Ada*_*oll 45 c# oop inheritance design-patterns

我不确定这是否是一件奇怪的事情,或者是否有一些代码闻起来...但我想知道是否有某种方式(某种oop模式会很好)来"施放"基类型到其派生类型的形式.我知道这没有多大意义,因为派生类型将具有父级不提供的附加功能,这在其本身并非基本健全.但有没有办法做到这一点?这是一个代码示例,以便我可以更好地解释我在问什么.

public class SomeBaseClass {
    public string GetBaseClassName {get;set;}
    public bool BooleanEvaluator {get;set;}
}

public class SomeDerivedClass : SomeBaseClass {
    public void Insert(SqlConnection connection) {
          //...random connection stuff
          cmd.Parameters["IsItTrue"].Value = this.BooleanEvalutar;
          //...
    }
}

public static void Main(object[] args) {
    SomeBaseClass baseClass = new SomeBaseClass();
    SomeDerivedClass derClass = (SomeDerivedClass)baseClass; 
    derClass.Insert(new sqlConnection());
}
Run Code Online (Sandbox Code Playgroud)

我知道这似乎很傻,但有没有办法完成这种事情?

Ada*_*ght 31

"管理"语言并不合理.这是向下转型,并有处理一下,整整你所说的原因,任何理智的一路下跌(子类,提供超过基类-在哪里呢这个"更"是从哪里来的?).如果您确实需要特定层次结构的类似行为,则可以将构造函数用于将基类型作为原型的派生类型.

可以用反射来构建一些处理简单情况的东西(更具体的类型没有添加状态).一般来说,只需重新设计即可避免此问题.

编辑:Woops,无法在基类/派生类型之间编写转换运算符.微软试图"保护你"对付自己的奇怪之处.好吧,至少他们没有像太阳那样差.

  • @KonradMorawski我指的是Java语言功能,旨在确保您编写"好"代码(其中"好"是他们的意见).我最讨厌被检查的异常(所以你*不能*只是忽略异常,永远). (4认同)

Rob*_*sor 18

尝试合成而不是继承!

在我看来,你最好将SomeBaseClass的一个实例传递给SomeDerivedClass(它将不再派生基类,并且应该重命名为这样)

public class BooleanHolder{       
    public bool BooleanEvaluator {get;set;}
}

public class DatabaseInserter{
    BooleanHolder holder;

    public DatabaseInserter(BooleanHolder holder){
        this.holder = holder;
    }

    public void Insert(SqlConnection connection) {
          ...random connection stuff
          cmd.Parameters["IsItTrue"].Value = holder.BooleanEvalutar;
          ...
    }
}

public static void Main(object[] args) {
    BooleanHolder h = new BooleanHolder();
    DatabaseInserter derClass = new DatabaseInserter(h);
    derClass.Insert(new sqlConnection);
}
Run Code Online (Sandbox Code Playgroud)

查看http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html(第3页):

通过组合重用代码组合为Apple提供了另一种方法,可以重用Fruit的peel()实现.Apple不是扩展Fruit,而是可以保存对Fruit实例的引用,并定义自己的peel()方法,只需在Fruit上调用peel()即可.

  • 虽然我赞成合成而非继承,但"苹果有果实"而不是"苹果是果实"的想法是我见过的最糟糕的例子.如果Apple定义了它自己的Peel方法,那么它就不再是Fruit的替代品 - 这类似于Fruit的整个概念. (16认同)

Rob*_*ick 15

就个人而言,我不认为在这种情况下使用继承的麻烦是值得的.而只是在构造函数中传递基类实例并通过成员变量访问它.

private class ExtendedClass //: BaseClass - like to inherit but can't
{
    public readonly BaseClass bc = null;
    public ExtendedClass(BaseClass b)
    {
        this.bc = b;
    }

    public int ExtendedProperty
    {
        get
        {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Mac*_*ehl 9

向下转换是有道理的,如果你有一个派生类的对象,但它被基类类型的引用引用,并且由于某种原因你希望它返回由派生类类型引用引用.换句话说,您可以向下转换以反转先前向上转换的效果.但是,您不能拥有由派生类类型的引用引用的基类对象.


Don*_* V. 7

我不是说我推荐这个.但是您可以将基类转换为JSON字符串,然后将其转换为派生类.

SomeDerivedClass layer = JsonConvert.DeserializeObject<SomeDerivedClass>(JsonConvert.SerializeObject(BaseClassObject));
Run Code Online (Sandbox Code Playgroud)

  • *"我不是说我推荐这个."* (3认同)

Der*_*ark 5

不,这是不可能的.在像C#这样的托管语言中,它只是不起作用.即使编译器允许,运行时也不会允许它.

你自己说这看起来很傻:

SomeBaseClass class = new SomeBaseClass();
SomeDerivedClass derClass = (SomeDerivedClass)class; 
Run Code Online (Sandbox Code Playgroud)

那么问问自己,class实际上是一个实例SomeDerivedClass吗?不,所以转换毫无意义.如果需要转换SomeBaseClassSomeDerivedClass,则应提供某种转换,无论是构造函数还是转换方法.

听起来好像你的类层次结构需要一些工作.通常,不应该将基类实例转换为派生类实例.通常应该存在不适用于基类的数据和/或功能.如果派生类功能适用于基类的所有实例,则它应该被卷入基类或拉入不属于基类层次结构的新类.


Ark*_*kun 5

C#语言不允许这样的操作符,但您仍然可以编写它们并且它们可以工作:

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Implicit(Base a) { ... }

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Explicit(Base a) { ... }
Run Code Online (Sandbox Code Playgroud)