Поля c # struct никогда не назначаются

2

На основе http://alexreg.wordpress.com/2009/05/03/strongly-typed-csv-reader-in-c/ я создал DLL, которая может читать разные типы файлов. У меня также есть модульные тесты, которые успешно выполняются. Я создаю структуру и использую ее как общий тип.

В любом случае, когда я компилирую, я получаю предупреждение по каждому из полей структуры. Например: поле "FileReader.Tests.CsvReader.Record.Field1" никогда не назначается и всегда будет иметь значение по умолчанию 0

Я фактически устанавливаю значение с помощью SetValueDirect(), и когда я запускаю тесты или отлаживаю код, я могу это проверить. Почему это дает мне эту ошибку, и как ее можно избежать или исправить?

Вот базовый код, который даст вам представление. Я предполагаю, что я не предоставил достаточно, но, надеюсь, у кого-то есть ключ.

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
    Возможно, было бы проще упростить ваш пример ...
  • 0
    Я начал это делать, но потом это показалось слишком упрощенным. Я полагаю, важная часть: fieldTypeInfo.FieldInfo.SetValueDirect (__ makeref (record), fieldValue);
Показать ещё 1 комментарий
Теги:
generics
struct

4 ответа

3
Лучший ответ

Компилятор никогда не сможет обнаружить отражение. По определению, используя отражение, вы вышли за пределы компилятора.

IMO, однако, это плохое использование структур - это очень похоже на то, что он должен работать над классами...

  • 0
    Что вы имеете в виду под "это должно работать на классах"? Структура строго определяет поля записи и атрибуты поля. Возможно, мне следует создать класс Record с помощью record.AddField ("name", typeof (int)) или чего-то подобного, но мне нравится простота и строгая типизация этого.
  • 0
    Во всяком случае, вы поднимаете хороший вопрос о Reflection. Я запутался тогда, почему я не получил эту ошибку раньше ...
Показать ещё 5 комментариев
1

Если вы используете struct вместо class, вы должны знать, почему вы это делаете.

Некоторые (редкие) случаи, когда вы должны использовать struct:

  • P/Invoke (когда нативная функция использует "structs" ) - это (imho) одна из причин, почему MS добавила struct в .NET(чтобы быть совместимой с собственным кодом)
  • structs - это так называемые типы значений. structs должно быть очень маленьким (например, struct DateTime, struct GpsCoordinates - это причины, использующие struct вместо классов, поскольку struct "быстрее", чем классы, потому что GC не нужно заботиться об этом.
  • Если вы не знаете, что использовать: используйте класс!!

- hfrmobile

1

Кажется, что компилятор не способен обнаруживать такие "косвенные" назначения. Он может обнаруживать только прямые назначения, такие как field=value.

В любом случае вы можете отключить специальные предупреждения компилятора. Предполагая, что вы используете Visual Studio, см. Здесь: http://msdn.microsoft.com/en-us/library/edzzzth4.aspx

  • 0
    Я бы согласился с вами, за исключением того, что эти предупреждения не появлялись рано. В какой-то момент (если бы я знал, когда!) Что-то, что я изменил, «сломало» это. Я посмотрю, смогу ли я как-нибудь сузить это.
0

Ненавижу, когда я изобретаю колесо. FileHelpers из http://www.filehelpers.com/ уже делает это очень похожим образом и, конечно же, охватывает более крайние случаи. Они определяют класс с атрибутами вместо структуры (как предположил Марк). Если вы установите определение записи как непубличное, вы получите те же предупреждения компилятора, которые я получал.

  • 0
    Теперь, когда я использую его еще немного, я должен сказать, что их реализация CSV (как видит конечный пользователь) не так чиста или проста в использовании, как моя. В любом случае, они проделали большую работу и, вероятно, лучше, чем я когда-либо делал.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню