2009-10-29 3 views
2

Basé sur http://alexreg.wordpress.com/2009/05/03/strongly-typed-csv-reader-in-c/, j'ai créé une DLL qui peut lire différents types de fichiers. J'ai aussi des tests unitaires qui fonctionnent avec succès. Je crée une structure et l'utilise comme type générique. Quoi qu'il en soit, quand je compile, j'obtiens un avertissement sur chacun des champs de la structure. Par exemple: le champ 'FileReader.Tests.CsvReader.Record.Field1' n'est jamais assigné à, et aura toujours sa valeur par défaut 0C# les champs struct sont des avertissements "never assigned to"

Je suis en train de définir la valeur avec SetValueDirect() et quand je passe les tests ou déboguer le code, je peux le vérifier. Pourquoi me donne-t-il alors cette erreur, et comment puis-je l'éviter ou la réparer?

Voici un code de base pour vous donner une idée. Je suppose que je n'ai pas fourni assez, mais j'espère que quelqu'un a une idée.

public abstract class FileReader<TRecord> : IDisposable where TRecord : struct 
{ 
     public TRecord? ReadRecord() 
     { 
      List<string> fields; 
      string rawData; 

      this.recordNumber++; 
      while (this.ReadRecord(this.fieldTypeInfoList.Length, out fields, out rawData)) 
      { 
       try 
       { 
        // Insert the current record number to the beginning of the field list 
        fields.Insert(0, this.recordNumber.ToString(CultureInfo.InvariantCulture)); 

        // Convert each field to its correct type and set the value 
        TRecord record = new TRecord(); 
        FieldTypeInfo fieldTypeInfo; 
        object fieldValue; 

        // Loop through each field 
        for (int i = 0; i < this.fieldTypeInfoList.Length; i++) 
        { 
         fieldTypeInfo = this.fieldTypeInfoList[i]; 

         bool allowNull = fieldTypeInfo.AllowNull == null ? this.AllowNull : fieldTypeInfo.AllowNull.Value; 
         if (i >= fields.Count && !allowNull) 
         { 
          // There are no field values for the current field 
          throw new ParseException("Field is missing", this.RecordNumber, fieldTypeInfo, rawData); 
         } 
         else 
         { 
          // Trim the field value 
          bool trimSpaces = fieldTypeInfo.TrimSpaces == null ? this.TrimSpaces : fieldTypeInfo.TrimSpaces.Value; 
          if (trimSpaces) 
          { 
           fields[i] = fields[i].Trim(); 
          } 

          if (fields[i].Length == 0 && !allowNull) 
          { 
           throw new ParseException("Field is null", this.RecordNumber, fieldTypeInfo, rawData); 
          } 

          try 
          { 
           fieldValue = fieldTypeInfo.TypeConverter.ConvertFromString(fields[i]); 
          } 
          catch (Exception ex) 
          { 
           throw new ParseException("Could not convert field value", ex, this.RecordNumber, fieldTypeInfo, rawData); 
          } 

          fieldTypeInfo.FieldInfo.SetValueDirect(__makeref(record), fieldValue); 
         } 
        } 

        return record; 
       } 
       catch (ParseException ex) 
       { 
        ParseErrorAction action = (ex.FieldTypeInfo.ParseError == null) ? DefaultParseErrorAction : ex.FieldTypeInfo.ParseError.Value; 

        switch (action) 
        { 
         case ParseErrorAction.SkipRecord: 
          continue; 

         case ParseErrorAction.ThrowException: 
          throw; 

         case ParseErrorAction.RaiseEvent: 
          throw new NotImplementedException("Events are not yet available", ex); 

         default: 
          throw new NotImplementedException("Unknown ParseErrorAction", ex); 
        } 
       } 
      } 

      return null; 
     } 
} 
+0

il aurait été plus facile de simplifier votre exemple ... Je –

+0

commencé à le faire, mais il me semblait trop simplifié le rôle important que je suppose est la suivante:. fieldTypeInfo .FieldInfo.SetValueDirect (__ makeref (record), fieldValue); –

+0

Le point est: sans l'exemple le plus simple, nous pouvons ' t reproduire ce que vous voyez ... donc un peu difficile de répondre avec confiance. –

Répondre

3

Le compilateur est jamais va pouvoir repérer la réflexion. Par définition, en utilisant la réflexion, vous êtes sorti du compilateur.

OMI, cependant, cela est une mauvaise utilisation de struct - qui ressemble beaucoup comme il devrait travailler sur les classes ...

+0

Que voulez-vous dire par «ça devrait marcher sur les cours»? La structure définit strictement les champs d'enregistrement et les attributs de champ. Peut-être que je devrais créer une classe Record avec record.AddField ("name", typeof (int)) ou quelque chose de similaire, mais j'aime la simplicité et le typage fort de ceci. –

+0

De toute façon, vous faites un bon point sur Reflection. Je suis confus alors pourquoi je n'obtenais pas cette erreur plus tôt ... –

+0

structs ne sont généralement pas destinés à représenter des «dossiers». Ils sont destinés à représenter des valeurs - des choses comme "26 GBP", etc. "Records" sont classiquement des objets = classes. Ne sois pas trompé; les structures surdimensionnées peuvent ** introduire ** des inefficacités. –

1

Il semble que le compilateur ne soit pas capable de détecter de telles affectations «indirectes». Il ne peut détecter que les affectations directes telles que field=value.

Vous pouvez quand même désactiver les avertissements spécifiques du compilateur. En supposant que vous utilisez Visual Studio, voir ici: http://msdn.microsoft.com/en-us/library/edzzzth4.aspx

+0

Je serais d'accord avec vous, sauf que ces avertissements ne venaient pas tôt. À un moment donné (j'aurais aimé savoir quand!), quelque chose que j'ai changé "cassé". Je vais voir si je peux le réduire d'une manière ou d'une autre. –

0

Je déteste quand je réinventer la roue. FileHelpers de http://www.filehelpers.com/ fait déjà cela d'une manière très similaire et couvre bien sûr plus de cas de bord. Ils ont vous définir une classe avec des attributs au lieu d'une structure (comme Marc suggéré). Si vous définissez leur définition d'enregistrement comme non publique, vous obtenez les mêmes avertissements de compilateur que je recevais.

+0

Maintenant que je l'utilise encore plus, je dois dire que leur implémentation CSV (vue par l'utilisateur final) n'est pas aussi propre ou facile à utiliser que la mienne. Quoi qu'il en soit, ils ont fait un excellent travail et probablement mieux que jamais. –

1

Si vous utilisez struct au lieu de classe vous devriez savoir pourquoi vous le faites.

Certains (rares) cas où vous devez utiliser struct:

  1. P/Invoke (lorsque la fonction native utilise des "struct") - c'est (AMHA) l'un des la raison pour laquelle MS a ajouté struct .NET (afin d'être compatible avec le code natif)
  2. Les structures sont appelées types de valeur. structs devrait être très petit (par exemple struct DateTime, struct GpsCoordinates sont des raisons utilisant struct au lieu de classes puisque struct sont "plus rapides" que les classes car le GC ne doit pas s'en soucier
  3. Si vous ne savez pas quoi utiliser: utiliser classe !!

--hfrmobile