// Copyright 2009-2022 Josh Close // This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. // See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. // https://github.com/JoshClose/CsvHelper using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace CsvHelper.Expressions { /// /// Base implementation for classes that write records. /// public abstract class RecordWriter { private readonly Dictionary typeActions = new Dictionary(); /// /// Gets the writer. /// protected CsvWriter Writer { get; private set; } /// /// The expression manager. /// protected ExpressionManager ExpressionManager { get; private set; } /// /// Initializes a new instance using the given writer. /// /// The writer. public RecordWriter(CsvWriter writer) { Writer = writer; ExpressionManager = ObjectResolver.Current.Resolve(writer); } /// /// Writes the record to the current row. /// /// Type of the record. /// The record. public void Write(T record) { try { GetWriteDelegate(record)(record); } catch (TargetInvocationException ex) { if (ex.InnerException != null) { throw ex.InnerException; } else { throw; } } } /// /// Gets the delegate to write the given record. /// If the delegate doesn't exist, one will be created and cached. /// /// The record type. /// The record. protected Action GetWriteDelegate(T record) { var type = typeof(T); var typeKeyName = type.AssemblyQualifiedName; if (type == typeof(object)) { type = record.GetType(); typeKeyName += $"|{type.AssemblyQualifiedName}"; } int typeKey = typeKeyName.GetHashCode(); if (!typeActions.TryGetValue(typeKey, out Delegate action)) { typeActions[typeKey] = action = CreateWriteDelegate(record); } return (Action)action; } /// /// Creates a of type /// that will write the given record using the current writer row. /// /// The record type. /// The record. protected abstract Action CreateWriteDelegate(T record); /// /// Combines the delegates into a single multicast delegate. /// This is needed because Silverlight doesn't have the /// Delegate.Combine( params Delegate[] ) overload. /// /// The delegates to combine. /// A multicast delegate combined from the given delegates. protected virtual Action CombineDelegates(IEnumerable> delegates) { return (Action)delegates.Aggregate(null, Delegate.Combine); } } }