为什么VB不允许从父类到子类的类型转换?

问题描述:

我已经提出了一个问题here,我基本上需要将基类的实例转换为子类(或使用基类属性的实例创建的子类的新实例)。结论似乎是这样做的最好方法是手动分配我需要在基类的构造函数中传输的每个属性。为什么VB不允许从父类到子类的类型转换?

尽管在某些情况下这是可行的,但它并不是在有很多属性需要传输时,或者基类可能会发生变化时 - 每次向基类添加属性时,构造函数都需要也改变了,所以这个解决方案不够优雅。

我已经在网上搜索,并且看不到为什么这种类型铸造没有实现的任何理由。我迄今为止所看到的论点描述了这种操作“没有任何意义”(从汽车中制作小型货车就是我看到的一个类比),质疑如何处理子类中的非继承变量,或者声称必须为尝试实现的目标提供更好的解决方案。

据我所知,只要有用,操作不需要“有意义”,所以这不是一个很好的理由。添加更多属性(也许方法/覆盖它们)将实例更改为子类有什么不妥?在非继承变量的情况下,只需通过允许这种类型转换就可以解决这个问题 - 只需将一个构造函数添加到子类中,或者只需将它们设置为其默认值。毕竟,施工人员通常都会拨打MyBase.New(...)。使用基础构造函数(基本上创建基础的新实例)和使用已经初始化的实例之间有什么区别?最后,我不认为第三个论点是合理的 - 有些时候所有其他解决方案都不够优雅。

所以最后,还有什么其他理由为什么这种铸造不被允许,并且有没有一种优雅的方法来规避这种情况?

编辑:

因为我不知道了很多关于这个话题,我想我的意思是说“转换”,而不是“投”。我还会添加一个示例来展示我试图成功的方式。只有在子类别初始化时才允许转换:

Class BaseClass 

Dim x as Integer 
Dim y as Integer 

End Class 


Class Subclass1 : Inherits BaseClass 

    Dim z as Integer 

    Sub New(Byval value As Integer) 
     'Standard initialisation method 

     MyBase.New() 

     z = value 
    End Sub 

    Sub New(Byval value As Integer, Byval baseInstance As BaseClass) 
     'Type conversion from base class to subclass 

     baseInstance.passAllproperties() 
'This assigns all properties of baseInstance belonging to BaseClass to Me. 
'Properties not in BaseClass (eg. if baseInstance is Subclass2) are ignored. 

     z = value 
    End Sub 
End Class 


Class Subclass2 : Inherits BaseClass 

    Dim v As Integer 
End Class 
+2

您需要更好地理解继承和多态。你不能将基础投射到后代,因为通常不可能这样做。你怎么能把一只动物当成一匹马来对待它,当那只动物可能是一只猫或一只海豹?当你试图把马鞍和马缰放在他们身上并将他们骑在你的院子周围时,猫和海豹会极力反对。如果你发现自己需要这样做,这是你的课程设计或实施得不好的迹象。 –

+0

@KenWhite我不同意。后裔在初始化时要求基地的一个实例用作模板有什么问题? – Shuri2060

+0

虽然这不是你的问题所要求的。你的问题是关于**基地**被投给**后代**,这是**完全相反的**。对于后代来说,要求父母(基础)实例是很好的;例如,它在调用基础构造函数时定期完成。你曾经问过做相反的事,这是你失败的地方。 –

使用System.Reflection遍历属性和基类的领域,并将其应用到派生类。此示例包含单个公共财产和单个公共领域,但也将与多个私有/受保护的属性和字段一起使用。您可以将整个示例粘贴到新的控制台应用程序中进行测试。

Imports System.Reflection 

Module Module1 

    Sub Main() 
     Dim p As New Parent 
     p.Property1 = "abc" 
     p.Field1 = "def" 
     Dim c = New Child(p) 
     Console.WriteLine("Property1 = ""{0}"", Field1 = ""{1}""", c.Property1, c.Field1) 
     Console.ReadLine() 
    End Sub 

    Class Parent 
     Public Property Property1 As String = "not set" 
     Public Property Field1 As String = "not set" 
    End Class 

    Class Child 
     Inherits Parent 
     Public Sub New(myParent As Parent) 
      Dim fieldInfo = GetType(Parent).GetFields(BindingFlags.NonPublic _ 
                 Or BindingFlags.Instance) 
      For Each field In fieldInfo 
       field.SetValue(Me, field.GetValue(myParent)) 
      Next 
      Dim propertyInfo = GetType(Parent).GetProperties(BindingFlags.NonPublic _ 
                  Or BindingFlags.Instance) 
      For Each prop In propertyInfo 
       prop.SetValue(Me, prop.GetValue(myParent)) 
      Next 
     End Sub 
    End Class 

End Module 

输出:

该解决方案是自动化的,所以你不需要改变任何添加或删除时

Property1 = “ABC”,字段1 = “高清”属性和基类中的字段。

+0

正如我所说的,我不想做这样的事情,因为每当编辑父类改变其属性,所有执行此操作的孩子也必须修改。 – Shuri2060

+0

然后使用反射遍历属性和字段(甚至私有),并将找到的所有内容都设置为派生类。 – djv

+0

你能链接我的例子或链接解释这个?我只能找到c# – Shuri2060

您描述的内容不是转换。你有没有听过“用不同的光线投射东西”这个表达方式?它意味着用不同的方式看待同一件事,或者让同样的事情看起来不同。这是编程中使用术语“投射”的确切方式。在投射时,您不会更改对象的类型,而只会改变用于访问对象的参考的类型。如果你想从一个基类型转换为派生类型,那么你所指的对象实际上就是那个派生类型。如果不是那么你不是演员,而是转换。

那么,为什么不能将基类型的实例转换为派生类型的实例。那么,你为什么能够?是的,这可能会节省时间编写一些代码,但它确实有意义吗?假设您有一个基本类型和一个属性,并且派生类型添加了另一个属性。我们还要说,派生类型具有要求您为第二个属性提供值的构造函数。您建议该语言应该为您提供一种将基类的实例魔术转换为派生类的实例的方法,这意味着它必须放慢您规避由作者通过构造函数定义的规则。为什么这会是一件好事?

+0

好的 - 因为我对这个知之甚少,所以把它叫做错误的名字。但至于第二点,我说你应该能够通过为子类创建一个新的初始化器来将一个基类转换为子类,该初始化器将基类的一个实例作为参数。我没有看到这与你如何调用MyBase.New(...)或super.init(...)有什么不同。)'(取决于语言) - 您仍然需要初始化该初始化程序中的任何非继承变量,因此您必须为新属性提供一个值。 – Shuri2060

+0

@QuestionAsker:这不是*铸造*,它与将基类转换为子类*无关。它被称为*遗传*,在那里(就像你从你父母或祖父母那里得到的那样),你**继承你的祖先的资产。正如我所说的,你需要更好地理解继承和多态。 –

在一般情况下,因为这样:

Class TheBase 
End Class 

Class Derived1 : TheBase 
    Sub Foo() 
    End Sub 
End Class 

Class Derived2 : TheBase 
    Sub Bar() 
    End Sub 
End Class 

Sub Main() 
    Dim myDerived1 As New Derived1 
    ' cast derived to base 
    Dim myTheBase = CType(myDerived1, TheBase) 
    ' cast base to derived? 
    ' but myTheBase is actually a Derived1 
    Dim myDerived2 As Derived2 = CType(myTheBase, Derived2) 
    ' which function call would you like to succeed? 
    myDerived2.Foo() 
    myDerived2.Bar() 
End Sub 
+0

我澄清了我在OP中的意思 - 我的意思是转换而不是铸造。所以在从Base转换到Subclass之后,只有属于Base的属性才会被转移。因此'myDerived2.Foo'将不存在。 – Shuri2060

+0

这里的要点是构建的唯一对象是Derived1。它不能更改为Derived2,因为它们可能有很多差异。你可以编写自己的方法来做到这一点,现在每个人都知道你不是在谈论铸造。 – djv