2017-07-18 6 views
2

Je suis en train de développer une application qui utilise le dispositif de mouvement de saut et qui sera implémentée en utilisant C#, mon problème est que je veux stocker la liste qui contient les vecteurs dans ma base de données. J'ai donc pensé à une solution de transformation du vecteur en un tableau de flottants, le problème est que chaque liste contient un maximum et un minimum de 300 valeurs (stocker cela dans la base de données prend beaucoup de temps)."Le type n'est pas prévu et aucun contrat ne peut être déduit: erreur Leap.Vector". en utilisant le sérialiseur Protobuf-net

J'ai donc cherché d'autres moyens possibles de stockage et j'ai fini sur le sujet de la sérialisation .net. J'avais essayé d'implémenter la sérialisation .net intégrée. Pensé que cela a fonctionné, mais encore une fois il aura fallu environ une minute de sérialiser la liste. Donc une autre solution proposée sur le sujet est d'utiliser le protobuf-net. donc je l'avais essayé et installé en utilisant le programme d'installation du paquet nuget. Et a fini avec cette fonction (copié de la solution Fastest way to serialize and deserialize .NET objects)

public static byte[] Serialize(List<Vector> tData) 
{ 
    using (var ms = new MemoryStream()) 
    { 
     ProtoBuf.Serializer.Serialize(ms, tData); 
     return ms.ToArray(); 
    } 
} 

public static List<Vector> Deserialize(byte[] tData) 
{ 
    using (var ms = new MemoryStream(tData)) 
    { 
     return ProtoBuf.Serializer.Deserialize<List<Vector>>(ms); 
    } 
} 

Mais l'exécution du code me conduire à l'erreur indiqué ci-dessus (le titre).

Je pense que l'erreur se produira à: ProtoBuf.Serializer.Serialize(ms, tData);

+0

A quoi 'Vector' ressemble-t-il? Les types dans protobuf-net peuvent être configurés à l'exécution, mais j'ai besoin de quelques indices sur ce à quoi cela ressemble ... est-ce que la bibliothèque est disponible sur nuget, par exemple? –

+0

Est-ce votre 'Leap.Vector'? https://developer.leapmotion.com/documentation/csharp/api/Leap.Vector.html Si oui, une solution identique à celle de [Aucun sérialiseur défini pour le type: System.Windows.Media.Media3D.Point3D] (https : //stackoverflow.com/q/33495897/3744182) devrait fonctionner. – dbc

+0

Je * soupçonne * que tout ce dont vous avez besoin est: 'RuntimeTypeModel.Default.Add (typeof (Vector), false) .Add (" X "," Y "," Z ");' quelque part au début de votre application, et ça va commencer à fonctionner. Il est heureux d'inférer des contrats pour des types de type tuple, mais dans ce cas je pense qu'il y a des propriétés calculées supplémentaires qui le rendent confus (ne sachant pas comment mapper les propriétés calculées au constructeur). Très difficile à dire sans accès à 'Vector', cependant. L'approche de substitution associée à @dbc est une autre option. –

Répondre

0

@dbc a déjà lié à un code similaire re Point3D, mais je me demande si toute sérialiseur est nécessaire ici. Cela semble assez simple juste cru (note que j'ai supposé que float est le type de données sous-jacente ici, sinon, il suffit de changer tous les sizeof(float) et float* du type correct):

static unsafe byte[] Serialize(List<Vector> vectors) 
{ 
    var arr = new byte[3 * sizeof(float) * vectors.Count]; 
    fixed(byte* ptr = arr) 
    { 
     var typed = (float*)ptr; 
     foreach(var vec in vectors) 
     { 
      *typed++ = vec.X; 
      *typed++ = vec.Y; 
      *typed++ = vec.Z; 
     } 
    } 
    return arr; 
} 
static unsafe List<Vector> Deserialize(byte[] arr) 
{ 
    int count = arr.Length/(3 * sizeof(float)); 
    var vectors = new List<Vector>(count); 
    fixed (byte* ptr = arr) 
    { 
     var typed = (float*)ptr; 
     for(int i = 0; i < count; i++) 
     { 
      var x = *typed++; 
      var y = *typed++; 
      var z = *typed++; 
      vectors.Add(new Vector(x, y, z)); 
     }    
    } 
    return vectors; 
} 

Si vous êtes vraiment courageux, vous pouvez également essayer de vider les données sous-jacentes directement plutôt que de copier les champs manuellement; cela vaut la peine d'essayer si sizeof(Vector) est exactement 3 * sizeof(float) (ou quel que soit le type sous-jacent).

+0

Je suis désolé pour la réponse tardive monsieur et je vous remercie pour la réponse immédiate. Le code ci-dessus fonctionne magnifiquement! Attention à expliquer comment ces fonctions fonctionnent. C'est toujours la première fois que je rencontre des codes dangereux. Et pourquoi le processus n'a pas besoin de sérialisation du tout? – Neelneel

+0

@Neelneel le code montré * est * sérialisation; le point que je faisais est que vous n'avez probablement pas besoin d'une bibliothèque de sérialisation complète pour ce scénario.Si nous regardons la méthode 'Serialize', ce que cela fait est: créer un nouveau tableau de la taille requise (3 valeurs par vecteur); obtenir un pointeur temporairement épinglé aux données du tableau (qui sera un pointeur "byte *"); contraindre cela dans un pointeur 'float *' - en disant essentiellement "ce pointeur: agir comme si c'était un pointeur sur les données' float' "; alors nous itérons sur les valeurs, et pour chacune, nous écrivons les valeurs X, Y, Z dans cet ordre; (partie 1 de 2) –

+0

@Neelneel le '* tapé ++ = {une certaine valeur};' est très subtil - '* tapé = {une certaine valeur}' par lui-même serait "assign {une certaine valeur} à la mémoire pointée par le pointeur 'typed'" - c'est-à-dire "write' X' à 'typed'"; 'typed ++' par lui-même serait "incrémenter le pointeur par sa taille attendue" - c'est-à-dire "se déplacer tapé en avant par un' float', donc il pointe vers l'espace suivant ". Mis ensemble, ils font tout cela en une seule opération, notant que 'typed ++ 'est ** post ** - incrément, donc nous écrivons' X' etc à l'emplacement ** vieux **, pas le ** nouvel ** emplacement . Donc: ceci écrit les 3 valeurs et on finit 12 octets plus loin; avoir un sens? –