我不确定这是否是一件奇怪的事情,或者是否有一些代码味道...但我想知道是否有某种方法(某种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());
}

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

有帮助吗?

解决方案

不合理,在“管理”中语言。这是向下转换,并且没有理智的方法来处理它,正是因为你描述的原因(子类提供的不仅仅是基类 - 这个“更多”来自哪里?)。如果您确实需要特定层次结构的类似行为,则可以将构造函数用于将基类型作为原型的派生类型。

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

编辑:Woops,无法在基类/派生类型之间编写转换运算符。微软试图“保护你”的奇怪之处反对自己。好吧,至少他们不像太阳那么差。

其他提示

尝试使用合成而不是继承!

在我看来,你最好将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);
}

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

  

通过合成组合重用代码   为Apple提供了另一种方式   重用Fruit的实现   剥()。而不是延伸水果,   Apple可以提供Fruit的参考   实例并定义自己的peel()   简单地调用peel()的方法   水果。

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

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
        {
        }
    }
}

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

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

SomeDerivedClass layer = JsonConvert.DeserializeObject<SomeDerivedClass>(JsonConvert.SerializeObject(BaseClassObject));

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

你自己说这看起来很傻:

SomeBaseClass class = new SomeBaseClass();
SomeDerivedClass derClass = (SomeDerivedClass)class; 

那么问问自己, class 实际上是 SomeDerivedClass 的一个实例?不,所以转换毫无意义。如果您需要将 SomeBaseClass 转换为 SomeDerivedClass ,那么您应该提供某种转换,无论是构造函数还是转换方法。

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

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

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

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

是的 - 这是一种代码味道,并且几乎指出了你的继承链被破坏的事实。

我的猜测(来自有限的样本)是你宁愿让DerivedClass对SomeBaseClass的一个实例进行操作 - 所以“DerivedClass 有一个 SomeBaseClass”,而不是“DerivedClass SomeBaseClass”。这被称为“赞成组合而不是继承”。

正如其他人所说,你建议的演员阵容真的不可能。 是否可能是装饰模式(Head First提取)可以的情况介绍?

您是否考虑过一个接口,即当前您的基类和派生类都将实现?我不知道为什么你这样做的具体细节,但它可能有效。

这被称为向下倾斜,而塞尔达克建议使用“安全”。版本很合理。

这是一个相当不错的代码示例说明

这是不可能的,因为你怎么会得到“额外”的?派生类有。当你实例化它时,编译器如何知道你的意思是derivedClass1而不是derivedClass2?

我认为您真正需要的是工厂模式或类似工具,因此您可以在不知道实例化的显式类型的情况下实例化对象。在您的示例中,使用“插入”按钮方法将是工厂返回实例的实例的接口。

我不知道为什么没有人这么说,我可能会错过一些东西,但你可以使用as关键字,如果你需要使用if语句,请使用if。

SomeDerivedClass derClass = class as SomeDerivedClass; //derClass is null if it isnt SomeDerivedClass
if(class is SomeDerivedClass)
    ;

-edit- 很久以前我问过这个问题

我最近一直需要使用派生类型扩展一个简单的DTO,以便在其上添加更多属性。然后我想重用一些转换逻辑,从内部数据库类型到DTO。

我解决它的方法是在DTO类上强制执行一个空构造函数,使用它如下:

class InternalDbType {
    public string Name { get; set; }
    public DateTime Date { get; set; }
    // Many more properties here...
}

class SimpleDTO {
    public string Name { get; set; }
    // Many more properties here...
}

class ComplexDTO : SimpleDTO {
    public string Date { get; set; }
}

static class InternalDbTypeExtensions {
    public static TDto ToDto<TDto>(this InternalDbType obj) where TDto : SimpleDTO, new() {
        var dto = new TDto {
            Name = obj.Name
        }
    }
}

然后我可以在转换为复杂的DTO时重用简单DTO中的转换逻辑。当然,我必须以其他方式填写复杂类型的属性,但是简单DTO的许多属性,这真的简化了IMO。

那不行。查看由编译错误链接的帮助页面。

最好的解决方案是在这里使用工厂方法。

正如许多答案所指出的那样,你不能贬低哪个是完全有道理的。

但是,在您的情况下, SomeDerivedClass 没有“缺失”的属性。所以你可以创建一个像这样的扩展方法:

public static T ToDerived<T>(this SomeBaseClass baseClass) 
    where T:SomeBaseClass, new()
{
    return new T()
    {
        BooleanEvaluator = baseClass.BooleanEvaluator,
        GetBaseClassName = baseClass.GetBaseClassName
    };
}

所以你不是在施法,只是转换:

SomeBaseClass b = new SomeBaseClass();
SomeDerivedClass c = b.ToDerived<SomeDerivedClass>();

只有当基类中的所有数据都是可读写属性时才能正常工作。

C ++使用构造函数处理它。 C ++ Typecasting 。这似乎是对我的疏忽。你们中的许多人提出了这个过程对额外属性的影响。我会回答,当程序员没有设置属性时,编译器在创建派生类时会做什么?我已经处理过与C ++类似的情况。我创建一个构造函数,它接受基类,然后在构造函数中手动设置属性。这绝对比在派生类中设置变量和破坏继承更可取。我也会通过工厂方法选择它,因为我认为生成的代码看起来会更干净。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top