I am having a strange issue where CsvHelper does not change properties that use classpaths to save data eg set => Channel.Snippet.Title
or set => Channel.Id
.
using (StreamReader fileStream = new StreamReader(openFileDialog.FileName))
using (CsvReader reader = new CsvReader(fileStream, new CsvConfiguration(CultureInfo.InvariantCulture)
{
DetectColumnCountChanges = false,
HeaderValidated = (args) => // This is set because the CSV is only partial data
{
Console.WriteLine(args.ToString());
},
MissingFieldFound = null // This is set because the CSV is only partial data
}))
{
foreach (FullChannel record in reader.GetRecords<FullChannel>()) // tried adding .ToList()
{
Settings.Default.Channels.Add(record); // record.Id and record.Title are both null
Console.WriteLine($"Id: {record.Id} Title: {record.Title}"); // Logs: Id: Title:
record.Id = "foo"; // This works fine
record.Title = "bar"; // This works fine too
Console.WriteLine($"Id: {record.Id} Title: {record.Title}"); // Logs: Id: foo Title: bar
}
}
This always deserializes the correct amount. I've tried to create a new TestChannel
, clean and rebuild. CsvHelper seems to be able to save if there is no classpath eg using private string title
in Title
(The commented out code).
using Google.Apis.YouTube.v3.Data;
public class FullChannel
{
private string title;
public FullChannel()
{
Channel.Snippet = new ChannelSnippet();
}
// Functionality
public DateTime LastUpdated { get; set; }
public bool AllNotifications { get; set; }
// Channel
/// <summary>
/// Warning: Nothing in this property gets saved
/// </summary>
[XmlIgnore]
//public Channel Channel { get; set; } = new Channel(); // this is the original code
public TestChannel Channel { get; set; } = new TestChannel(); // this doesn't work for Id or Title
// For csv
[Name("Channel Id")]
public string Id { get => Channel.Id; set => Channel.Id = value; }
[Name("Channel Url")]
[XmlIgnore] // Generated value only
public string Url { get => $"https://www.youtube.com/channel/{Channel.Id}"; set => _ = value; }
[Name("Channel Title")]
public string Title {
//get => title;
//set => title = value;
get => Channel.Snippet.Title;
set => Channel.Snippet.Title = value;
}
}
public class TestChannel
{
public ChannelSnippet Snippet { get; set; }
public string Id { get; set; }
}
CodePudding user response:
I have a feeling that the way CsvHelper reconstitutes the class is not recognizing the classpaths. The only thing I can suggest is saving directly to Channel.Snippet.Title
and Channel.Id
.
void Main()
{
using (var fileStream = new StringReader("Channel Id,Channel Url,Channel Title\n1,this.com,MyTitle"))
using (CsvReader reader = new CsvReader(fileStream, new CsvConfiguration(CultureInfo.InvariantCulture)
{
DetectColumnCountChanges = false,
HeaderValidated = (args) => // This is set because the CSV is only partial data
{
Console.WriteLine(args.ToString());
},
MissingFieldFound = null // This is set because the CSV is only partial data
}))
{
reader.Context.RegisterClassMap<FullChannelMap>();
foreach (FullChannel record in reader.GetRecords<FullChannel>()) // tried adding .ToList()
{
Console.WriteLine($"Id: {record.Id} Title: {record.Title}"); // Logs: Id: Title:
record.Id = "foo"; // This works fine
record.Title = "bar"; // This works fine too
Console.WriteLine($"Id: {record.Id} Title: {record.Title}"); // Logs: Id: foo Title: bar
}
}
}
public class FullChannelMap : ClassMap<FullChannel>
{
public FullChannelMap()
{
Map(x => x.Channel.Id).Name("Channel Id");
Map(x => x.Channel.Snippet.Title).Name("Channel Title");
Map(x => x.Url).Name("Channel Url");
}
}