2010-04-22 3 views
2

J'ai une exception très étrange dans mon application C#: lors d'une tentative de désérialisation d'une classe contenant un List<IListMember> générique (où les entrées de la liste sont spécifiées par une interface), une exception est générée "le type ... IListMember n'est pas marqué avec l'attribut sérialisable" (le phrasé peut être légèrement différent, mon VisualStudio n'est pas en anglais).Interface "non marqué avec l'attribut sérialisable" exception

Maintenant, les interfaces ne peuvent pas être sérialisables; la classe réellement contenue dans la liste, implémentant IListMember, est[Serializable]; et oui, j'ai vérifié que IListMember est en fait défini comme une interface et non accidentellement comme une classe!

J'ai essayé de reproduire l'exception dans un projet de test séparé contenant uniquement la classe contenant la liste et les membres, mais il sérialise et désérialise joyeusement:/

Est-ce que quelqu'un a des bonnes idées sur ce qu'il pourrait être ?

Edit:

Nous utilisons un BinarySerializer; et je le répète, une fois extrait dans un projet de test, la classe se sérialise avec bonheur. Donc je n'ai pas besoin d'une solution de contournement pour sérialiser une classe contenant un List<IThing>, car en général cela fonctionne très bien (tant que les classes réelles implémentant IThing sont sérialisables); ce que je cherche est des raisons pour lesquelles il pourrait pas travail ce moment ...

Je vais maintenant mettre dans une solution de contournement (sérialisation chaque membre de la liste individuellement, ainsi que le nombre d'entrées, et recréant l'List par main), mais aimerait vraiment savoir ce que cela pourrait être pour référence future.

+2

Quel sérialiseur utilisez-vous? 'BinaryFormatter'? 'XmlSerializer'? 'DataContractSerializer'? "Sérialiseur organique maison de Bob"? Également - y a-t-il des 'événements 'impliqués? –

+0

Voir ma modification; et oui, il y a des événements impliqués quelque part le long de la ligne menant à l'appel de binaryFormatter.Deserialize; voyez-vous une connexion? –

+0

L'interface est utilisée pour déterminer si la classe indique qu'elle peut être sérialisée, si vous avez une liste de références basées sur une interface, où l'interface n'est pas marquée comme sérialisable, peut-être que le code de sérialisation essaie de vous dire objets ici qu'il ne peut pas traiter? Même si votre graphique d'objet actuel est A-OK. –

Répondre

-1

The Easy Way (Même si laid) Enveloppez votre liste:

public ListMemberCollection : List<IListMember>, ISerializable 
{ 
    // Implement ISerializable Here 
} 

La voie alternative (Bien mieux) AbstractBaseClass:

[Serializable] 
public ListMemberBase : IListMember 
{ 
    // Implement abstract versions of everything 
} 

Une possibilité ?: (Sur l'autre classe)

class TheClassYoureSerializing 
{ 
    [Serializable] 
    public List<IListMember> list { get; set; } 
} 
+0

Je ne comprends pas. La classe implémentant IListMember ** est ** [Serializable] - pourquoi devrais-je créer une classe de base abstraite supplémentaire? –

2

Peu importe que la classe supportant l'interface soit sérialisable. Les interfaces ne peuvent pas être sérialisées, point.

Pour deserialize, le sérialiseur doit être en mesure d'instancier un type de béton, et il détermine ce type en réfléchissant sur les champs/propriétés de la classe à être-désérialisé.

Si le type d'une de ces propriétés est une interface, il ne sera jamais capable de construire un type concret à affecter à ce membre. Tout ce qu'il voit est l'interface, il n'a aucune idée de la classe qui l'a implémenté à l'origine quand les données ont été sérialisées.

Si vous souhaitez que la classe soit sérialisable, chaque classe dans le graphe d'objet doit être un type concret. Aucune interface autorisée. (Postscript: En fait, j'ai en quelque sorte menti, le BinaryFormatter peut sérialiser/désérialiser directement vers/à partir des types d'interface, mais je soupçonne fortement que ce n'est pas ce qui est utilisé ici.

+0

Non, pas vrai; nous utilisons en effet BinaryFormatter; et il peut en effet sérialiser des classes même si elles ne sont déclarées que via une interface. Le ** type ** de la classe reste le type concret, qui est, comme vous le dites, susceptible de réflexion; Le fait qu'il soit déclaré dans la propriété de classe uniquement via une interface ne change pas cela. –

Questions connexes