135 votes

Incapable de transtyper d'une classe parent à une classe enfant

J'essaie de convertir une classe parent en classe enfant, mais j'obtiens une exception InvalidCastException. La classe enfant n'a qu'une propriété de type int. Est-ce que quelqu'un sait ce que je dois faire?

199voto

Arcturus Points 417

Un moyen simple de décoder en C # consiste à sérialiser le parent, puis à le désérialiser dans l'enfant.

  var serializedParent = JsonConvert.SerializeObject(parentInstance); 
 Child c  = JsonConvert.DeserializeObject<Child>(serializedAnimal);
 

J'ai une application console simple qui transforme un animal en chien, en utilisant les deux lignes de code ci-dessus ici

153voto

cjk Points 27463

Vous ne pouvez pas lancer un mammifère sur un chien - ce peut être un chat.

Vous ne pouvez pas jeter un aliment dans un sandwich - ce pourrait être un cheeseburger.

Vous ne pouvez pas lancer une voiture dans une Ferrari - il peut s'agir d'une Honda, ou plus précisément, vous ne pouvez pas lancer une Ferrari 360 Modena sur une Ferrari 360 Challange Stradale - il existe différentes parties, même si elles sont toutes les deux Ferrari 360.

62voto

Greg D Points 24218

L'instance à laquelle fait référence votre référence de classe de base n'est pas une instance de votre classe enfant. Il n'y a rien de mal.

Plus précisement:

 Base derivedInstance = new Derived();
Base baseInstance = new Base();

Derived good = (Derived)derivedInstance; // OK
Derived fail = (Derived)baseInstance; // Throws InvalidCastException
 

Pour que la conversion réussisse, l’instance à laquelle vous effectuez un downcast doit être une instance de la classe à laquelle vous effectuez un downcast (ou au moins, la classe à laquelle vous effectuez un downcast doit appartenir à la hiérarchie des classes de l’instance). le casting échouera.

20voto

Mehdi LAMRANI Points 3961

Il existe des cas où un tel casting aurait du sens.
J'mon cas, j'ai reçu une classe de BASE sur le réseau, et j'ai besoin de plus de fonctionnalités. Donc dériver à gérer de mon côté, avec toutes les cloches et de sifflets que je voulais, et le casting du reçu de la classe de BASE dans la DÉRIVÉE on était tout simplement pas une option (Jette InvalidCastException bien Sûr)

Un think-out-of-the-box SOLUTION a été de déclarer une EXTENSION de la classe Helper qui n'était PAS hériter de la classe de BASE en fait, mais y COMPRIS en tant que membre.

public class BaseExtension
{
   Base baseInstance;

   public FakeDerived(Base b)
   {
      baseInstance = b;
   }

   //Helper methods and extensions to Base class added here
}

Si vous avez couplage lâche et juste besoin d'un couple de fonctionnalités supplémentaires de la classe de base sans VRAIMENT avoir un besoin absolu de dérivation, qui pourrait être un moyen rapide et simple de contourner le problème.

9voto

FastAl Points 3414

Paul, vous n'avez pas de demander: "puis-je le faire" - je suppose que vous voulez savoir comment le faire!

Nous avons dû faire un projet - il y a beaucoup de classes nous avons mis en place dans le générique de la mode une fois seulement, puis initialiser les propriétés spécifiques aux classes dérivées. J'utilise VB donc mon exemple est en VB (dur noogies), mais j'ai volé le VB de l'échantillon à partir de ce site, qui dispose également d'une meilleure version de C#:

http://www.eggheadcafe.com/tutorials/aspnet/a4264125-fcb0-4757-9d78-ff541dfbcb56/net-reflection--copy-cl.aspx

Exemple de code:

Imports System
Imports System.Collections.Generic
Imports System.Reflection
Imports System.Text
Imports System.Diagnostics

Module ClassUtils

    Public Sub CopyProperties(ByVal dst As Object, ByVal src As Object)
        Dim srcProperties() As PropertyInfo = src.GetType.GetProperties
        Dim dstType = dst.GetType

        If srcProperties Is Nothing Or dstType.GetProperties Is Nothing Then
            Return
        End If

        For Each srcProperty As PropertyInfo In srcProperties
            Dim dstProperty As PropertyInfo = dstType.GetProperty(srcProperty.Name)

            If dstProperty IsNot Nothing Then
                If dstProperty.PropertyType.IsAssignableFrom(srcProperty.PropertyType) = True Then
                    dstProperty.SetValue(dst, srcProperty.GetValue(src, Nothing), Nothing)
                End If
            End If
        Next
    End Sub
End Module


Module Module1
    Class base_class
        Dim _bval As Integer
        Public Property bval() As Integer
            Get
                Return _bval
            End Get
            Set(ByVal value As Integer)
                _bval = value
            End Set
        End Property
    End Class
    Class derived_class
        Inherits base_class
        Public _dval As Integer
        Public Property dval() As Integer
            Get
                Return _dval
            End Get
            Set(ByVal value As Integer)
                _dval = value
            End Set
        End Property
    End Class
    Sub Main()
        ' NARROWING CONVERSION TEST
        Dim b As New base_class
        b.bval = 10
        Dim d As derived_class
        'd = CType(b, derived_class) ' invalidcast exception 
        'd = DirectCast(b, derived_class) ' invalidcast exception
        'd = TryCast(b, derived_class) ' returns 'nothing' for c
        d = New derived_class
        CopyProperties(d, b)
        d.dval = 20
        Console.WriteLine(b.bval)
        Console.WriteLine(d.bval)
        Console.WriteLine(d.dval)
        Console.ReadLine()
    End Sub
End Module

Bien sûr, ce n'est pas vraiment de la coulée. C'est la création d'un nouveau dérivé de l'objet et de copier les propriétés de la société mère, en laissant l'enfant propriétés vide. C'est tout ce que j'avais à faire, et il semblerait que son tout ce que vous devez faire. Remarque il copie seulement les propriétés non-membres (variables publiques) dans la classe (mais vous pouvez l'étendre pour le faire si vous êtes à la honte d'exposer le public et les membres).

Casting en général crée 2 variables pointant vers le même objet (mini tutoriel ici, merci de ne pas jeter le coin des cas d'exceptions à moi). Il y a d'importantes ramifications pour ce (exercice au lecteur)!

Bien sûr, je dois dire pourquoi le languague ne pas vous laisser aller à partir de la base de dériver de l'instance, mais la autre façon. imaginer un cas où vous pouvez prendre un exemple d'un winforms zone de texte (dérivés) et de le stocker dans une variable de type Winforms de contrôle. Bien sûr, le "contrôle" peut déplacer l'objet sur OK et vous pouvez faire face à tous les "controll-y' de choses sur la zone de texte (p. ex., haut, gauche, .les propriétés de texte). La zone de texte spécifique des choses (par exemple, .multiline) ne peut pas être vu sans le casting du "contrôle" type de variable pointant sur la zone de texte dans la mémoire, mais il est toujours là dans la mémoire.

Maintenant, imaginez, vous avez un contrôle, et vous voulez le cas d'une variable de type zone de texte pour elle. Le Contrôle de la mémoire est manquant "multiline" et d'autres textboxy choses. Si vous essayez de faire référence à eux, le contrôle n'est pas comme par magie cultiver une propriété multiline! La propriété (le considérer comme une variable de membre ici, qui stocke en fait une valeur, car il est dans la zone de texte instance de mémoire) doit exister. Puisque vous êtes casting, rappelez-vous, il doit être le même objet que vous pointez. Il n'est donc pas une restriction de langue, il est philosophiquement impossible de cas d'une telle manière.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X