На основе 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;
}
}
Компилятор никогда не сможет обнаружить отражение. По определению, используя отражение, вы вышли за пределы компилятора.
IMO, однако, это плохое использование структур - это очень похоже на то, что он должен работать над классами...
Если вы используете struct вместо class, вы должны знать, почему вы это делаете.
Некоторые (редкие) случаи, когда вы должны использовать struct:
- hfrmobile
Кажется, что компилятор не способен обнаруживать такие "косвенные" назначения. Он может обнаруживать только прямые назначения, такие как field=value
.
В любом случае вы можете отключить специальные предупреждения компилятора. Предполагая, что вы используете Visual Studio, см. Здесь: http://msdn.microsoft.com/en-us/library/edzzzth4.aspx
Ненавижу, когда я изобретаю колесо. FileHelpers из http://www.filehelpers.com/ уже делает это очень похожим образом и, конечно же, охватывает более крайние случаи. Они определяют класс с атрибутами вместо структуры (как предположил Марк). Если вы установите определение записи как непубличное, вы получите те же предупреждения компилятора, которые я получал.