Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/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#_Oop_Inheritance_Design Patterns - Fatal编程技术网

C# 将基类型强制转换为派生类型的一种方法

C# 将基类型强制转换为派生类型的一种方法,c#,oop,inheritance,design-patterns,C#,Oop,Inheritance,Design Patterns,我不确定这是否是一件奇怪的事情,或者这是代码的味道……但我想知道是否有一种方法(某种oop模式会很好)将基类型“强制转换”为其派生类型的形式。我知道这没有什么意义,因为派生类型将具有父级不提供的附加功能,而父级本身并不健全。但是有什么方法可以做到这一点吗?下面是一个代码示例,以便更好地解释我的问题 我知道这看起来很愚蠢,但是有没有办法完成这类事情呢?在“托管”语言中做得不太好。这是向下投射,没有一种明智的向下处理方法,原因正是您所描述的(子类提供的不仅仅是基类——这“更多”来自哪里?)。如果您确

我不确定这是否是一件奇怪的事情,或者这是代码的味道……但我想知道是否有一种方法(某种oop模式会很好)将基类型“强制转换”为其派生类型的形式。我知道这没有什么意义,因为派生类型将具有父级不提供的附加功能,而父级本身并不健全。但是有什么方法可以做到这一点吗?下面是一个代码示例,以便更好地解释我的问题

我知道这看起来很愚蠢,但是有没有办法完成这类事情呢?

在“托管”语言中做得不太好。这是向下投射,没有一种明智的向下处理方法,原因正是您所描述的(子类提供的不仅仅是基类——这“更多”来自哪里?)。如果您确实希望特定层次结构具有类似的行为,则可以将构造函数用于将基类型作为原型的派生类型

可以使用反射构建一些东西来处理简单的情况(没有附加状态的更具体的类型)


编辑:Woops,无法在基类型/派生类型之间编写转换运算符。这是Microsoft试图“保护您”自己的一个奇怪现象。啊,好吧,至少它们没有Sun那么糟糕。

这无法工作。请查看由编译错误链接的帮助页


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

这被称为向下广播,Seldaek建议使用“安全”版本是正确的


这是一个相当不错的方法。

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

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

你自己说这看起来很愚蠢:

SomeBaseClass class = new SomeBaseClass();
SomeDerivedClass derClass = (SomeDerivedClass)class; 
所以问问你自己,
class
实际上是
SomeDerivedClass
的一个实例吗?不,所以转换没有意义。如果你需要将
SomeBaseClass
转换为
SomeDerivedClass
,那么你应该提供某种转换,或者是构造函数,或者是转换方法


不过,听起来您的类层次结构需要一些工作。通常,不可能将基类实例转换为派生类实例。通常应该有不适用于基类的数据和/或功能。如果派生类功能适用于基类的所有实例,则应该ld要么被汇总到基类中,要么被拉到一个不属于基类层次结构的新类中。

这是不可能的,因为您将如何获得派生类所拥有的“额外”。当您实例化它时,编译器如何知道您指的是derivedClass1而不是derivedClass2


我认为您真正需要的是工厂模式或类似模式,这样您就可以实例化对象,而不必真正了解正在实例化的显式类型方法将是工厂返回实现的实例的接口。

是的-这是一种代码味道,并且几乎确定了继承链已断开的事实


我的猜测(从有限的示例中)是,您更希望让DerivedClass对SomeBaseClass的实例进行操作,这样“DerivedClass有一个SomeBaseClass”,而不是“DerivedClass是一个SomeBaseClass”。这被称为“偏爱组合而不是继承”。

尝试组合而不是继承

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

退房(第3页):

通过组合实现代码重用 为苹果提供了另一种方式 重用水果的实现 剥()。而不是延长果实, 苹果可以引用水果 实例并定义其自己的剥离() 方法,该方法仅在 水果


正如其他人所指出的,你所建议的演员阵容实际上是不可能的。
可能会引入(头优先提取)吗?

您是否考虑过一个接口,当前您的基类和派生类都将实现这个接口?我不知道为什么要用这种方式实现,但它可能会起作用。

我不知道为什么没有人这么说,我可能遗漏了一些东西,但您可以使用as关键字,如果需要使用if语句,请使用if

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

-编辑-

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

我最近需要用派生类型扩展一个简单的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
        }
    }
}
public static T ToDerived<T>(this SomeBaseClass baseClass) 
    where T:SomeBaseClass, new()
{
    return new T()
    {
        BooleanEvaluator = baseClass.BooleanEvaluator,
        GetBaseClassName = baseClass.GetBaseClassName
    };
}
类内部数据库类型{
公共字符串Na
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
        }
    }
}
SomeDerivedClass layer = JsonConvert.DeserializeObject<SomeDerivedClass>(JsonConvert.SerializeObject(BaseClassObject));
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
        {
        }
    }
}
[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Implicit(Base a) { ... }

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Explicit(Base a) { ... }
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>();